[
  {
    "path": ".github/workflows/ci.yml",
    "content": "# This file was automatically generated by sbt-github-actions using the\n# githubWorkflowGenerate task. You should add and commit this file to\n# your git repository. It goes without saying that you shouldn't edit\n# this file by hand! Instead, if you wish to make changes, you should\n# change your sbt build configuration to revise the workflow description\n# to meet your needs, then regenerate this file.\n\nname: Continuous Integration\n\non:\n  pull_request:\n    branches: ['**']\n  push:\n    branches: ['**']\n\nenv:\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\njobs:\n  build:\n    name: Build and Test\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n        scala: [2.12.14, 2.13.6, 3.0.2]\n        java: [adopt@1.8]\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Checkout current branch (full)\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n          submodules: recursive\n\n      - name: Setup Java and Scala\n        uses: olafurpg/setup-scala@v13\n        with:\n          java-version: ${{ matrix.java }}\n\n      - name: Cache sbt\n        uses: actions/cache@v2\n        with:\n          path: |\n            ~/.sbt\n            ~/.ivy2/cache\n            ~/.coursier/cache/v1\n            ~/.cache/coursier/v1\n            ~/AppData/Local/Coursier/Cache/v1\n            ~/Library/Caches/Coursier/v1\n          key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}\n\n      - name: Check that workflows are up to date\n        run: sbt ++${{ matrix.scala }} githubWorkflowCheck\n\n      - name: Test\n        run: 'sbt ++${{ matrix.scala }} clean javacc coverage scalastyle scalafmtCheckAll scalafmtSbtCheck test slow:test coverageReport'\n\n      - uses: codecov/codecov-action@v1\n"
  },
  {
    "path": ".github/workflows/clean.yml",
    "content": "# This file was automatically generated by sbt-github-actions using the\n# githubWorkflowGenerate task. You should add and commit this file to\n# your git repository. It goes without saying that you shouldn't edit\n# this file by hand! Instead, if you wish to make changes, you should\n# change your sbt build configuration to revise the workflow description\n# to meet your needs, then regenerate this file.\n\nname: Clean\n\non: push\n\njobs:\n  delete-artifacts:\n    name: Delete Artifacts\n    runs-on: ubuntu-latest\n    env:\n      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n    steps:\n      - name: Delete artifacts\n        run: |\n          # Customize those three lines with your repository and credentials:\n          REPO=${GITHUB_API_URL}/repos/${{ github.repository }}\n\n          # A shortcut to call GitHub API.\n          ghapi() { curl --silent --location --user _:$GITHUB_TOKEN \"$@\"; }\n\n          # A temporary file which receives HTTP response headers.\n          TMPFILE=/tmp/tmp.$$\n\n          # An associative array, key: artifact name, value: number of artifacts of that name.\n          declare -A ARTCOUNT\n\n          # Process all artifacts on this repository, loop on returned \"pages\".\n          URL=$REPO/actions/artifacts\n          while [[ -n \"$URL\" ]]; do\n\n            # Get current page, get response headers in a temporary file.\n            JSON=$(ghapi --dump-header $TMPFILE \"$URL\")\n\n            # Get URL of next page. Will be empty if we are at the last page.\n            URL=$(grep '^Link:' \"$TMPFILE\" | tr ',' '\\n' | grep 'rel=\"next\"' | head -1 | sed -e 's/.*<//' -e 's/>.*//')\n            rm -f $TMPFILE\n\n            # Number of artifacts on this page:\n            COUNT=$(( $(jq <<<$JSON -r '.artifacts | length') ))\n\n            # Loop on all artifacts on this page.\n            for ((i=0; $i < $COUNT; i++)); do\n\n              # Get name of artifact and count instances of this name.\n              name=$(jq <<<$JSON -r \".artifacts[$i].name?\")\n              ARTCOUNT[$name]=$(( $(( ${ARTCOUNT[$name]} )) + 1))\n\n              id=$(jq <<<$JSON -r \".artifacts[$i].id?\")\n              size=$(( $(jq <<<$JSON -r \".artifacts[$i].size_in_bytes?\") ))\n              printf \"Deleting '%s' #%d, %'d bytes\\n\" $name ${ARTCOUNT[$name]} $size\n              ghapi -X DELETE $REPO/actions/artifacts/$id\n            done\n          done\n"
  },
  {
    "path": ".gitignore",
    "content": "*.iml\ntarget/\n.idea/\n.idea_modules/\n.DS_STORE\n.cache\n.settings\n.project\n.classpath\ntmp/\n.bloop/\n.metals/\n.bsp/\nproject/metals.sbt\nbazel-bin\nbazel-dhallj\nbazel-out\nbazel-testlogs\n.vscode/\nproject/project/\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"dhall-lang\"]\n\tpath = dhall-lang\n\turl = https://github.com/dhall-lang/dhall-lang.git\n"
  },
  {
    "path": ".scalafmt.conf",
    "content": "version=3.0.7\nalign.openParenCallSite = true\nalign.openParenDefnSite = true\nmaxColumn = 120\ncontinuationIndent.defnSite = 2\nassumeStandardLibraryStripMargin = true\ndanglingParentheses.preset = true\nrewrite.rules = [AvoidInfix, SortImports, RedundantParens, SortModifiers]\ndocstrings.style = Asterisk\nnewlines.alwaysBeforeMultilineDef = false\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2020, Travis Brown\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# Dhall for Java\n\n[![Build status](https://img.shields.io/github/workflow/status/travisbrown/dhallj/Continuous%20Integration.svg)](https://github.com/travisbrown/dhallj/actions)\n[![Gitter](https://img.shields.io/badge/gitter-join%20chat-green.svg)](https://gitter.im/dhallj/)\n[![Maven Central](https://img.shields.io/maven-central/v/org.dhallj/dhall-core.svg)](https://maven-badges.herokuapp.com/maven-central/org.dhallj/dhall-core)\n\nThis project is an implementation of the [Dhall][dhall-lang] configuration language for the Java\nVirtual Machine.\n\nOur goal for this project is to make it as easy as possible to integrate Dhall\ninto JVM build systems (see the [dhall-kubernetes] demonstration\n[below](#converting-to-other-formats) for a concrete example of why you might want to do this).\n\nThe core modules have no external dependencies, are Java 7-compatible, and are fairly minimal:\n\n```bash\n$ du -h modules/core/target/dhall-core-0.10.0-M1.jar\n168K    modules/core/target/dhall-core-0.10.0-M1.jar\n\n$ du -h modules/parser/target/dhall-parser-0.10.0-M1.jar\n108K    modules/parser/target/dhall-parser-0.10.0-M1.jar\n```\n\nThere are also several [Scala][scala] modules that are published for Scala 2.12,\n2.13, and 3.0. While most of the examples in this README are focused on Scala, you\nshouldn't need to know or care about Scala to use the core DhallJ modules.\n\nThe initial development of this project was supported in part by [Permutive][permutive].\n\n## Table of contents\n\n* [Status](#status)\n* [Getting started](#getting-started)\n* [Converting to other formats](#converting-to-other-formats)\n* [Import resolution](#import-resolution)\n* [Command-line interface](#command-line-interface)\n* [Other stuff](#other-stuff)\n* [Developing](#developing)\n* [Community](#community)\n* [Copyright and license](#copyright-and-license)\n\n## Status\n\nThe current release of this project supports [Dhall 21.0.0][dhall-21-0-0].\nWe're running the [Dhall acceptance test suites][dhall-tests] for parsing, normalization,\n[CBOR][cbor] encoding and decoding, hashing, and type inference, and\ncurrently all tests are passing (with three exceptions; see the [0.10.0-M1 release notes for details](https://github.com/travisbrown/dhallj/releases/tag/v0.10.0-M1)).\n\nThere are several known issues:\n\n* The parser [cannot parse deeply nested structures](https://github.com/travisbrown/dhallj/issues/2) (records, etc., although note that indefinitely long lists are fine).\n* The type checker is [also not stack-safe](https://github.com/travisbrown/dhallj/issues/3) (this should be fixed soon).\n* Import resolution is not provided in the core modules, and is a work in progress.\n\nWhile we think the project is reasonably well-tested, it's very new, is sure to be full of bugs, and\nnothing about the API should be considered stable at the moment. Please use responsibly.\n\n## Getting started\n\nThe easiest way to try things out is to add the Scala wrapper module to your build.\nIf you're using [sbt][sbt] that would look like this:\n\n```scala\nlibraryDependencies += \"org.dhallj\" %% \"dhall-scala\" % \"0.10.0-M1\"\n```\n\nThis dependency includes two packages: `org.dhallj.syntax` and `org.dhallj.ast`.\n\nThe `syntax` package provides some extension methods, including a `parseExpr`\nmethod for strings (note that this method returns an\n`Either[ParsingFailure, Expr]`, which we unwrap here with `Right`):\n\n```scala\nscala> import org.dhallj.syntax._\nimport org.dhallj.syntax._\n\nscala> val Right(expr) = \"\\\\(n: Natural) -> [n + 0, n + 1, 1 + 1]\".parseExpr\nexpr: org.dhallj.core.Expr = λ(n : Natural) → [n + 0, n + 1, 1 + 1]\n```\n\nNow that we have a Dhall expression, we can type-check it:\n\n```scala\nscala> val Right(exprType) = expr.typeCheck\nexprType: org.dhallj.core.Expr = ∀(n : Natural) → List Natural\n```\n\nWe can \"reduce\" (or _β-normalize_) it:\n\n```scala\nscala> val normalized = expr.normalize\nnormalized: org.dhallj.core.Expr = λ(n : Natural) → [n, n + 1, 2]\n```\n\nWe can also _α-normalize_ it, which replaces all named variables with\nindexed underscores:\n\n```scala\nscala> val alphaNormalized = normalized.alphaNormalize\nalphaNormalized: org.dhallj.core.Expr = λ(_ : Natural) → [_, _ + 1, 2]\n```\n\nWe can encode it as a CBOR byte array:\n\n```scala\nscala> alphaNormalized.getEncodedBytes\nres0: Array[Byte] = Array(-125, 1, 103, 78, 97, 116, 117, 114, 97, 108, -123, 4, -10, 0, -124, 3, 4, 0, -126, 15, 1, -126, 15, 2)\n```\n\nAnd we can compute its semantic hash:\n\n```scala\nscala> alphaNormalized.hash\nres1: String = c57cdcdae92638503f954e63c0b3ae8de00a59bc5e05b4dd24e49f42aca90054\n```\n\nIf we have the official `dhall` CLI installed, we can confirm that this hash is\ncorrect:\n\n```bash\n$ dhall hash <<< '\\(n: Natural) -> [n + 0, n + 1, 1 + 1]'\nsha256:c57cdcdae92638503f954e63c0b3ae8de00a59bc5e05b4dd24e49f42aca90054\n```\n\nWe can also compare expressions:\n\n```scala\nscala> val Right(other) = \"\\\\(n: Natural) -> [n, n + 1, 3]\".parseExpr\nother: org.dhallj.core.Expr = λ(n : Natural) → [n, n + 1, 3]\n\nscala> normalized == other\nres2: Boolean = false\n\nscala> val Some(diff) = normalized.diff(other)\ndiff: (Option[org.dhallj.core.Expr], Option[org.dhallj.core.Expr]) = (Some(2),Some(3))\n```\n\nAnd apply them to other expressions:\n\n```scala\nscala> val Right(arg) = \"10\".parseExpr\narg: org.dhallj.core.Expr = 10\n\nscala> expr(arg)\nres3: org.dhallj.core.Expr = (λ(n : Natural) → [n + 0, n + 1, 1 + 1]) 10\n\nscala> expr(arg).normalize\nres4: org.dhallj.core.Expr = [10, 11, 2]\n```\n\nWe can also resolve expressions containing imports (although at the moment\ndhall-scala doesn't support remote imports or caching; please see the\n[section on import resolution](#import-resolution) below for details about\nhow to set up remote import resolution if you need it):\n\n```scala\nval Right(enumerate) =\n     |   \"./dhall-lang/Prelude/Natural/enumerate\".parseExpr.flatMap(_.resolve)\nenumerate: org.dhallj.core.Expr = let enumerate : Natural → List Natural = ...\n\nscala> enumerate(arg).normalize\nres5: org.dhallj.core.Expr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\n\nNote that we're working with values of type `Expr`, which comes from dhall-core,\nwhich is a Java module. The `Expr` class includes static methods for creating\n`Expr` values:\n\n```scala\nscala> import org.dhallj.core.Expr\nimport org.dhallj.core.Expr\n\nscala> Expr.makeTextLiteral(\"foo\")\nres6: org.dhallj.core.Expr = \"foo\"\n\nscala> Expr.makeEmptyListLiteral(Expr.Constants.BOOL)\nres7: org.dhallj.core.Expr = [] : Bool\n```\n\nIf you're working from Scala, though, you're generally better off using the\nconstructors included in the `org.dhallj.ast` package, which provide more\ntype-safety:\n\n```scala\nscala> TextLiteral(\"foo\")\nres8: org.dhallj.core.Expr = \"foo\"\n\nscala> NonEmptyListLiteral(BoolLiteral(true), Vector())\nres9: org.dhallj.core.Expr = [True]\n```\n\nThe `ast` package also includes extractors that let you pattern match on\n`Expr` values:\n\n```scala\nscala> expr match {\n     |   case Lambda(name, _, NonEmptyListLiteral(first +: _)) => (name, first)\n     | }\nres10: (String, org.dhallj.core.Expr) = (n,n + 0)\n```\n\nNote that we don't have exhaustivity checking for these extractors, although we\nmight be able to add that in an eventual Dotty version.\n\nIn addition to dhall-scala, there's a (more experimental) dhall-scala-codec\nmodule, which supports encoding and decoding Scala types to and from Dhall expressions.\nIf you add it to your build, you can write the following:\n\n```scala\nscala> import org.dhallj.codec.syntax._\nimport org.dhallj.codec.syntax._\n\nscala> List(List(1, 2), Nil, List(3, -4)).asExpr\nres0: org.dhallj.core.Expr = [[+1, +2], [] : List Integer, [+3, -4]]\n```\n\nYou can even decode Dhall functions into Scala functions (assuming you have the\nappropriate codecs for the input and output types):\n\n```scala\nval Right(f) = \"\"\"\n\n  let enumerate = ./dhall-lang/Prelude/Natural/enumerate\n\n  let map = ./dhall-lang/Prelude/List/map\n\n  in \\(n: Natural) ->\n    map Natural Integer Natural/toInteger (enumerate n)\n\n\"\"\".parseExpr.flatMap(_.resolve)\n```\nAnd then:\n\n```scala\nscala> val Right(scalaEnumerate) = f.as[BigInt => List[BigInt]]\nscalaEnumerate: BigInt => List[BigInt] = org.dhallj.codec.Decoder$$anon$11$$Lambda$15614/0000000050B06E20@94b036\n\nscala> scalaEnumerate(BigInt(3))\nres1: List[BigInt] = List(0, 1, 2)\n```\n\nEventually we'll probably support generic derivation for encoding Dhall\nexpressions to and from algebraic data types in Scala, but we haven't\nimplemented this yet.\n\n## Converting to other formats\n\nDhallJ currently includes several ways to export Dhall expressions to other formats. The core module\nincludes very basic support for printing Dhall expressions as JSON:\n\n```scala\nscala> import org.dhallj.core.converters.JsonConverter\nimport org.dhallj.core.converters.JsonConverter\n\nscala> import org.dhallj.parser.DhallParser.parse\nimport org.dhallj.parser.DhallParser.parse\n\nscala> val expr = parse(\"(λ(n: Natural) → [n, n + 1, n + 2]) 100\")\nexpr: org.dhallj.core.Expr.Parsed = (λ(n : Natural) → [n, n + 1, n + 2]) 100\n\nscala> JsonConverter.toCompactString(expr.normalize)\nres0: String = [100,101,102]\n```\n\nThis conversion supports the same subset of Dhall expressions as [`dhall-to-json`][dhall-json] (e.g.\nit can't produce JSON representation of functions, which means the normalization in the example\nabove is necessary—if we hadn't normalized the conversion would fail).\n\nThere's also a module that provides integration with [Circe][circe], allowing you to convert Dhall\nexpressions directly to (and from) `io.circe.Json` values without intermediate serialization to\nstrings:\n\n```scala\nscala> import org.dhallj.circe.Converter\nimport org.dhallj.circe.Converter\n\nscala> import io.circe.syntax._\nimport io.circe.syntax._\n\nscala> Converter(expr.normalize)\nres0: Option[io.circe.Json] =\nSome([\n  100,\n  101,\n  102\n])\n\nscala> Converter(List(true, false).asJson)\nres1: org.dhallj.core.Expr = [True, False]\n```\n\nAnother module supports converting to any JSON representation for which you have a [Jawn][jawn]\nfacade. For example, the following build configuration would allow you to export [spray-json]\nvalues:\n\n```scala\nlibraryDependencies ++= Seq(\n  \"org.dhallj\"    %% \"dhall-jawn\" % \"0.4.0\",\n  \"org.typelevel\" %% \"jawn-spray\" % \"1.0.0\"\n)\n```\n\nAnd then:\n\n```scala\nscala> import org.dhallj.jawn.JawnConverter\nimport org.dhallj.jawn.JawnConverter\n\nscala> import org.typelevel.jawn.support.spray.Parser\nimport org.typelevel.jawn.support.spray.Parser\n\nscala> val toSpray = new JawnConverter(Parser.facade)\ntoSpray: org.dhallj.jawn.JawnConverter[spray.json.JsValue] = org.dhallj.jawn.JawnConverter@be3ffe1d\n\nscala> toSpray(expr.normalize)\nres0: Option[spray.json.JsValue] = Some([100,101,102])\n```\n\nNote that unlike the dhall-circe module, the integration provided by dhall-jawn is only one way\n(you can convert Dhall expressions to JSON values, but not the other way around).\n\nWe also support YAML export via [SnakeYAML][snake-yaml] (which doesn't require a Scala dependency):\n\n```scala\nscala> import org.dhallj.parser.DhallParser.parse\nimport org.dhallj.parser.DhallParser.parse\n\nscala> import org.dhallj.yaml.YamlConverter\nimport org.dhallj.yaml.YamlConverter\n\nscala> val expr = parse(\"{foo = [1, 2, 3], bar = [4, 5]}\")\nexpr: org.dhallj.core.Expr.Parsed = {foo = [1, 2, 3], bar = [4, 5]}\n\nscala> println(YamlConverter.toYamlString(expr))\nfoo:\n- 1\n- 2\n- 3\nbar:\n- 4\n- 5\n```\n\nYou can use the YAML exporter with [dhall-kubernetes], for example. Instead of\nmaintaining a lot of verbose and repetitive and error-prone YAML files, you can\nkeep your configuration in well-typed Dhall files (like\n[this example](https://github.com/dhall-lang/dhall-kubernetes/blob/506d633e382872346927b8cb9884d8b7382e6cab/1.17/examples/deploymentSimple.dhall))\nand have your build system export them to YAML:\n\n```scala\nimport org.dhallj.syntax._, org.dhallj.yaml.YamlConverter\n\nval kubernetesExamplePath = \"../dhall-kubernetes/1.17/examples/deploymentSimple.dhall\"\nval Right(kubernetesExample) = kubernetesExamplePath.parseExpr.flatMap(_.resolve)\n```\n\nAnd then:\n\n```scala\nscala> println(YamlConverter.toYamlString(kubernetesExample.normalize))\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx\nspec:\n  replicas: 2\n  selector:\n    matchLabels:\n      name: nginx\n  template:\n    metadata:\n      name: nginx\n    spec:\n      containers:\n      - image: nginx:1.15.3\n        name: nginx\n        ports:\n        - containerPort: 80\n```\n\nIt's not currently possible to convert to YAML without the SnakeYAML dependency, although we may support a simplified\nversion of this in the future (something similar to what we have for JSON in the core module).\n\n## Import resolution\n\nThere are currently two modules that implement import resolution (to different degrees).\n\n### dhall-imports\n\nThe first is dhall-imports, which is a Scala library built on [cats-effect] that uses [http4s] for\nits HTTP client. This module is intended to be a complete implementation of the\n[import resolution and caching specification][dhall-imports].\n\nIt requires a bit of ceremony to set up:\n\n```scala\nimport cats.effect.{IO, Resource}\nimport org.dhallj.core.Expr\nimport org.dhallj.imports.syntax._\nimport org.dhallj.parser.DhallParser\nimport org.http4s.blaze.client.BlazeClientBuilder\nimport org.http4s.client.Client\nimport scala.concurrent.ExecutionContext\n\nval client: Resource[IO, Client[IO]] = BlazeClientBuilder[IO](ExecutionContext.global).resource\n```\n\nAnd then if we have some definitions like this:\n\n```scala\nval concatSepImport = DhallParser.parse(\"https://prelude.dhall-lang.org/Text/concatSep\")\n\nval parts = DhallParser.parse(\"\"\"[\"foo\", \"bar\", \"baz\"]\"\"\")\nval delimiter = Expr.makeTextLiteral(\"-\")\n```\n\nWe can use them with a function from the Dhall Prelude like this:\n\n```scala\nscala> val resolved = client.use { implicit c =>\n     |   concatSepImport.resolveImports[IO]\n     | }\nresolved: cats.effect.IO[org.dhallj.core.Expr] = IO(...)\n\nscala> import cats.effect.unsafe.implicits.global\nimport cats.effect.unsafe.implicits.global\n\nscala> val result = resolved.map { concatSep =>\n     |   Expr.makeApplication(concatSep, Array(delimiter, parts)).normalize\n     | }\nresult: cats.effect.IO[org.dhallj.core.Expr] = IO(...)\n\nscala> result.unsafeRunSync()\nres0: org.dhallj.core.Expr = \"foo-bar-baz\"\n```\n\n(Note that we could use dhall-scala to avoid the use of `Array` above.)\n\n#### Classpath imports\n\nWe support an extension of the spec which allows you to also import expressions\nfrom the classpath using the syntax `let e = classpath:/absolute/path/to/file in e`.\nThe semantics are subject to change as we get more experience with it but\ncurrently it should generally have the same behaviour as an absolute\npath import of a local file (but files on the classpath can import each other\nusing relative paths). This includes it being protected by the referential\nsanity check so that remote imports cannot exfiltrate information\nfrom the classpath.\n\nAlso note that classpath imports as location are currently not supported as the spec\nrequires that an import as Location must return an expression of type\n`<Local Text | Remote Text | Environment Text | Missing>`.\n\n### dhall-imports-mini\n\nThe other implementation is dhall-imports-mini, which is a Java library that\ndepends only on the core and parser modules, but that doesn't support\nremote imports or caching.\n\nThe previous example could be rewritten as follows using dhall-imports-mini\nand a local copy of the Prelude:\n\n```scala\nimport org.dhallj.core.Expr\nimport org.dhallj.imports.mini.Resolver\nimport org.dhallj.parser.DhallParser\n\nval concatSep = Resolver.resolve(DhallParser.parse(\"./dhall-lang/Prelude/Text/concatSep\"), false)\n\nval parts = DhallParser.parse(\"\"\"[\"foo\", \"bar\", \"baz\"]\"\"\")\nval delimiter = Expr.makeTextLiteral(\"-\")\n```\n\nAnd then:\n\n```scala\nscala> Expr.makeApplication(concatSep, Array(delimiter, parts)).normalize\nres0: org.dhallj.core.Expr = \"foo-bar-baz\"\n```\n\nIt's likely that eventually we'll provide a complete pure-Java implementation of import resolution,\nbut this isn't currently a high priority for us.\n\n## Command-line interface\n\nWe include a command-line interface that supports some common operations. It's currently similar to\nthe official `dhall` and `dhall-to-json` binaries, but with many fewer options.\n\nIf [GraalVM Native Image][graal-native-image] is available on your system, you can build the CLI as\na native binary (thanks to [sbt-native-packager]).\n\n```bash\n$ sbt cli/graalvm-native-image:packageBin\n\n$ cd cli/target/graalvm-native-image/\n\n$ du -h dhall-cli\n8.2M    dhall-cli\n\n$ time ./dhall-cli hash --normalize --alpha <<< \"λ(n: Natural) → [n, n + 1]\"\nsha256:a8d9326812aaabeed29412e7b780dc733b1e633c5556c9ea588e8212d9dc48f3\n\nreal    0m0.009s\nuser    0m0.000s\nsys     0m0.009s\n\n$ time ./dhall-cli type <<< \"{foo = [1, 2, 3]}\"\n{foo : List Natural}\n\nreal    0m0.003s\nuser    0m0.000s\nsys     0m0.003s\n\n$ time ./dhall-cli json <<< \"{foo = [1, 2, 3]}\"\n{\"foo\":[1,2,3]}\n\nreal    0m0.005s\nuser    0m0.004s\nsys     0m0.001s\n```\n\nEven on the JVM it's close to usable, although you can definitely feel the slow startup:\n\n```bash\n$ cd ..\n\n$ time java -jar ./cli-assembly-0.4.0-SNAPSHOT.jar hash --normalize --alpha <<< \"λ(n: Natural) → [n, n + 1]\"\nsha256:a8d9326812aaabeed29412e7b780dc733b1e633c5556c9ea588e8212d9dc48f3\n\nreal    0m0.104s\nuser    0m0.106s\nsys     0m0.018s\n```\n\nThere's probably not really any reason you'd want to use `dhall-cli` right now, but I think it's a\npretty neat demonstration of how Graal can make Java (or Scala) a viable language for building\nnative CLI applications.\n\n## Other stuff\n\n### dhall-testing\n\nThe dhall-testing module provides support for property-based testing with [ScalaCheck][scalacheck]\nin the form of `Arbitrary` (and `Shrink`) instances:\n\n```scala\nscala> import org.dhallj.core.Expr\nimport org.dhallj.core.Expr\n\nscala> import org.dhallj.testing.instances._\nimport org.dhallj.testing.instances._\n\nscala> import org.scalacheck.Arbitrary\nimport org.scalacheck.Arbitrary\n\nscala> Arbitrary.arbitrary[Expr].sample\nres0: Option[org.dhallj.core.Expr] = Some(Optional (Optional (List Double)))\n\nscala> Arbitrary.arbitrary[Expr].sample\nres1: Option[org.dhallj.core.Expr] = Some(Optional (List <neftfEahtuSq : Double | kg...\n```\n\nIt includes (fairly basic) support for producing both well-typed and probably-not-well-typed\nexpressions, and for generating arbitrary values of specified Dhall types:\n\n```scala\nscala> import org.dhallj.testing.WellTypedExpr\nimport org.dhallj.testing.WellTypedExpr\n\nscala> Arbitrary.arbitrary[WellTypedExpr].sample\nres2: Option[org.dhallj.testing.WellTypedExpr] = Some(WellTypedExpr(8436008296256993755))\n\nscala> genForType(Expr.Constants.BOOL).flatMap(_.sample)\nres3: Option[org.dhallj.core.Expr] = Some(True)\n\nscala> genForType(Expr.Constants.BOOL).flatMap(_.sample)\nres4: Option[org.dhallj.core.Expr] = Some(False)\n\nscala> genForType(Expr.makeApplication(Expr.Constants.LIST, Expr.Constants.INTEGER)).flatMap(_.sample)\nres5: Option[org.dhallj.core.Expr] = Some([+1522471910085416508, -9223372036854775809, ...\n```\n\nThis module is currently fairly minimal, and is likely to change substantially in future releases.\n\n### dhall-javagen and dhall-prelude\n\nThe dhall-javagen module lets you take a DhallJ representation of a Dhall expression and use it to\ngenerate Java code that will build the DhallJ representation of that expression.\n\nThis is mostly a toy, but it allows us for example to distribute a \"pre-compiled\" jar containing the\nDhall Prelude:\n\n```scala\nscala> import java.math.BigInteger\nimport java.math.BigInteger\n\nscala> import org.dhallj.core.Expr\nimport org.dhallj.core.Expr\n\nscala> val ten = Expr.makeNaturalLiteral(new BigInteger(\"10\"))\nten: org.dhallj.core.Expr = 10\n\nscala> val Prelude = org.dhallj.prelude.Prelude.instance\nPrelude: org.dhallj.core.Expr = ...\n\nscala> val Natural = Expr.makeFieldAccess(Prelude, \"Natural\")\nNatural: org.dhallj.core.Expr = ...\n\nscala> val enumerate = Expr.makeFieldAccess(Natural, \"enumerate\")\nenumerate: org.dhallj.core.Expr = ...\n\nscala> Expr.makeApplication(enumerate, ten).normalize\nres0: org.dhallj.core.Expr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n```\n\nNote that the resulting jar (which is available from Maven Central as dhall-prelude) is many times\nsmaller than either the Prelude source or the Prelude serialized as CBOR.\n\n## Developing\n\nThe project includes the currently-supported version of the Dhall language repository as a\nsubmodule, so if you want to run the acceptance test suites, you'll need to clone recursively:\n\n```bash\ngit clone --recurse-submodules git@github.com:travisbrown/dhallj.git\n```\n\nOr if you're like me and always forget to do this, you can initialize the submodule after cloning:\n\n```bash\ngit submodule update --init\n```\n\nThis project is built with [sbt][sbt], and you'll need to have sbt [installed][sbt-installation]\non your machine.\n\nWe're using the [JavaCC][javacc] parser generator for the parsing module, and we have\n[our own sbt plugin][sbt-javacc] for integrating JavaCC into our build. This plugin is open source\nand published to Maven Central, so you don't need to do anything to get it, but you will need to run\nit manually the first time you build the project (or any time you update the JavaCC grammar):\n\n```\nsbt:root> javacc\nJava Compiler Compiler Version 7.0.5 (Parser Generator)\nFile \"Provider.java\" does not exist.  Will create one.\nFile \"StringProvider.java\" does not exist.  Will create one.\nFile \"StreamProvider.java\" does not exist.  Will create one.\nFile \"TokenMgrException.java\" does not exist.  Will create one.\nFile \"ParseException.java\" does not exist.  Will create one.\nFile \"Token.java\" does not exist.  Will create one.\nFile \"SimpleCharStream.java\" does not exist.  Will create one.\nParser generated with 0 errors and 1 warnings.\n[success] Total time: 0 s, completed 12-Apr-2020 08:48:53\n```\n\nAfter this is done, you can run the tests:\n\n```\nsbt:root> test\n...\n[info] Passed: Total 1319, Failed 0, Errors 0, Passed 1314, Skipped 5\n[success] Total time: 36 s, completed 12-Apr-2020 08:51:07\n```\n\nNote that a few tests require the [dhall-haskell] `dhall` CLI. If you don't have it installed on\nyour machine, these tests will be skipped.\n\nThere are also a few additional slow tests that must be run manually:\n\n```\nsbt:root> slow:test\n...\n[info] Passed: Total 4, Failed 0, Errors 0, Passed 4\n[success] Total time: 79 s (01:19), completed 12-Apr-2020 08:52:41\n```\n\n## Community\n\nThis project supports the [Scala code of conduct][code-of-conduct] and wants all of its channels\n(Gitter, GitHub, etc.) to be inclusive environments.\n\n## Copyright and license\n\nAll code in this repository is available under the [3-Clause BSD License][bsd-license].\n\nCopyright [Travis Brown][travisbrown] and [Tim Spence][timspence], 2020.\n\n[bsd-license]: https://opensource.org/licenses/BSD-3-Clause\n[cats-effect]: https://github.com/typelevel/cats-effect\n[cbor]: https://cbor.io/\n[circe]: https://github.com/circe/circe\n[code-of-conduct]: https://www.scala-lang.org/conduct/\n[dhall-21-0-0]: https://github.com/dhall-lang/dhall-lang/pull/1194\n[dhall-haskell]: https://github.com/dhall-lang/dhall-haskell\n[dhall-imports]: https://github.com/dhall-lang/dhall-lang/blob/master/standard/imports.md\n[dhall-json]: https://docs.dhall-lang.org/tutorials/Getting-started_Generate-JSON-or-YAML.html\n[dhall-kubernetes]: https://github.com/dhall-lang/dhall-kubernetes\n[dhall-tests]: https://github.com/dhall-lang/dhall-lang/tree/master/tests\n[dhall-lang]: https://dhall-lang.org/\n[discipline]: https://github.com/typelevel/discipline\n[graal-native-image]: https://www.graalvm.org/docs/reference-manual/native-image/\n[http4s]: https://http4s.org\n[javacc]: https://javacc.github.io/javacc/\n[jawn]: https://github.com/typelevel/jawn\n[permutive]: https://permutive.com\n[permutive-medium]: https://medium.com/permutive\n[sbt]: https://www.scala-sbt.org\n[sbt-installation]: https://www.scala-sbt.org/1.x/docs/Setup.html\n[sbt-javacc]: https://github.com/travisbrown/sbt-javacc\n[sbt-native-packager]: https://github.com/sbt/sbt-native-packager\n[scala]: https://www.scala-lang.org\n[scalacheck]: https://www.scalacheck.org/\n[snake-yaml]: https://bitbucket.org/asomov/snakeyaml/\n[spray-json]: https://github.com/spray/spray-json\n[timspence]: https://github.com/TimWSpence\n[travisbrown]: https://twitter.com/travisbrown\n"
  },
  {
    "path": "WORKSPACE",
    "content": "workspace(name = \"org_dhallj\")\n\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\n\n# Load j2cl repository\nhttp_archive(\n    name = \"com_google_j2cl\",\n    strip_prefix = \"j2cl-master\",\n    url = \"https://github.com/google/j2cl/archive/master.zip\",\n)\n\nload(\"@com_google_j2cl//build_defs:repository.bzl\", \"load_j2cl_repo_deps\")\n\nload_j2cl_repo_deps()\n\nload(\"@com_google_j2cl//build_defs:rules.bzl\", \"setup_j2cl_workspace\")\n\nsetup_j2cl_workspace()\n"
  },
  {
    "path": "benchmarks/src/main/scala/org/dhallj/benchmarks/EncodingBenchmark.scala",
    "content": "package org.dhallj.benchmarks\n\nimport java.util.concurrent.TimeUnit\nimport org.openjdk.jmh.annotations._\nimport org.dhallj.core.Expr\nimport org.dhallj.prelude.Prelude\n\n/**\n * Compare the performance of various ways of folding JSON values.\n *\n * The following command will run the benchmarks with reasonable settings:\n *\n * > sbt \"benchmarks/jmh:run -i 10 -wi 10 -f 2 -t 1 org.dhallj.benchmarks.EncodingBenchmark\"\n */\n@State(Scope.Thread)\n@BenchmarkMode(Array(Mode.Throughput))\n@OutputTimeUnit(TimeUnit.SECONDS)\nclass EncodingBenchmark {\n  val prelude: Expr = Prelude.instance\n  val deep: Expr = (0 to 100000).foldLeft(Expr.makeDoubleLiteral(0)) { case (acc, i) =>\n    Expr.makeRecordLiteral(s\"a$i\", acc)\n  }\n\n  @Benchmark\n  def encodePreludeToBytes: Array[Byte] = prelude.getEncodedBytes\n\n  @Benchmark\n  def encodeDeepToBytes: Array[Byte] = deep.getEncodedBytes\n}\n"
  },
  {
    "path": "benchmarks/src/main/scala/org/dhallj/benchmarks/ParsingBenchmark.scala",
    "content": "package org.dhallj.benchmarks\n\nimport java.util.concurrent.TimeUnit\nimport org.openjdk.jmh.annotations._\nimport org.dhallj.core.Expr\nimport org.dhallj.parser.DhallParser\nimport org.dhallj.prelude.Prelude\n\n/**\n * Compare the performance of various ways of folding JSON values.\n *\n * The following command will run the benchmarks with reasonable settings:\n *\n * > sbt \"benchmarks/jmh:run -i 10 -wi 10 -f 2 -t 1 org.dhallj.benchmarks.ParsingBenchmark\"\n */\n@State(Scope.Thread)\n@BenchmarkMode(Array(Mode.Throughput))\n@OutputTimeUnit(TimeUnit.SECONDS)\nclass ParsingBenchmark {\n  val preludeAsString = Prelude.instance.toString\n\n  @Benchmark\n  def parsePrelude: Expr = DhallParser.parse(preludeAsString)\n}\n"
  },
  {
    "path": "build.sbt",
    "content": "import ReleaseTransformations._\n\nThisBuild / organization := \"org.dhallj\"\nThisBuild / crossScalaVersions := List(\"2.12.14\", \"2.13.6\", \"3.0.2\")\nThisBuild / scalaVersion := crossScalaVersions.value.filter(_.startsWith(\"2\")).last\n\nThisBuild / githubWorkflowJavaVersions := Seq(\"adopt@1.8\")\nThisBuild / githubWorkflowPublishTargetBranches := Nil\nThisBuild / githubWorkflowJobSetup := {\n  (ThisBuild / githubWorkflowJobSetup).value.toList.map {\n    case step @ WorkflowStep.Use(UseRef.Public(\"actions\", \"checkout\", \"v2\"), _, _, _, _, _) =>\n      step.copy(params = step.params.updated(\"submodules\", \"recursive\"))\n    case other => other\n  }\n}\nThisBuild / githubWorkflowBuild := Seq(\n  WorkflowStep.Sbt(\n    List(\n      \"clean\",\n      \"javacc\",\n      \"coverage\",\n      \"scalastyle\",\n      \"scalafmtCheckAll\",\n      \"scalafmtSbtCheck\",\n      \"test\",\n      \"slow:test\",\n      \"coverageReport\"\n    ),\n    id = None,\n    name = Some(\"Test\")\n  ),\n  WorkflowStep.Use(\n    UseRef.Public(\n      \"codecov\",\n      \"codecov-action\",\n      \"v1\"\n    )\n  )\n)\n\nval previousVersion = \"0.9.0-M1\"\nval catsVersion = \"2.6.1\"\nval circeVersion = \"0.14.1\"\nval jawnVersion = \"1.2.0\"\nval munitVersion = \"0.7.29\"\nval scalaCheckVersion = \"1.15.4\"\nval snakeYamlVersion = \"1.29\"\nval http4sVersion = \"0.23.6\"\n\nval testDependencies = Seq(\n  \"co.nstant.in\" % \"cbor\" % \"0.9\",\n  \"org.scalacheck\" %% \"scalacheck\" % scalaCheckVersion,\n  \"org.scalameta\" %% \"munit\" % munitVersion,\n  \"org.scalameta\" %% \"munit-scalacheck\" % munitVersion\n)\n\nval http4sDependencies = Seq(\n  \"org.typelevel\" %% \"cats-core\" % catsVersion,\n  \"org.typelevel\" %% \"cats-effect\" % \"3.2.9\",\n  \"org.http4s\" %% \"http4s-client\" % http4sVersion\n)\n\nval http4sBlazeClient =\n  \"org.http4s\" %% \"http4s-blaze-client\" % http4sVersion\n\nval compilerOptions = Seq(\n  \"-deprecation\",\n  \"-encoding\",\n  \"UTF-8\",\n  \"-feature\",\n  \"-language:existentials\",\n  \"-language:higherKinds\",\n  \"-unchecked\",\n  \"-Ywarn-dead-code\",\n  \"-Ywarn-numeric-widen\",\n  \"-Xfuture\",\n  \"-Ywarn-unused-import\"\n)\n\ndef priorTo2_13(scalaVersion: String): Boolean =\n  CrossVersion.partialVersion(scalaVersion) match {\n    case Some((2, minor)) if minor < 13 => true\n    case _                              => false\n  }\n\nval baseSettings = Seq(\n  libraryDependencies ++= testDependencies.map(_ % Test),\n  testFrameworks += new TestFramework(\"munit.Framework\"),\n  coverageEnabled := (if (scalaVersion.value.startsWith(\"3\")) false else coverageEnabled.value)\n)\n\nval javaSettings = Seq(\n  autoScalaLibrary := false,\n  crossPaths := false,\n  Compile / javacOptions ++= Seq(\"-source\", \"1.7\"),\n  Compile / compile / javacOptions ++= Seq(\"-target\", \"1.7\"),\n  mimaPreviousArtifacts := Set(\"org.dhallj\" % moduleName.value % previousVersion)\n)\n\nval scalaSettings = Seq(\n  mimaPreviousArtifacts := Set(\"org.dhallj\" %% moduleName.value % previousVersion),\n  scalacOptions ++= {\n    if (priorTo2_13(scalaVersion.value)) compilerOptions\n    else\n      compilerOptions.flatMap {\n        case \"-Ywarn-unused-import\" => Seq(\"-Ywarn-unused:imports\")\n        case \"-Xfuture\"             => Nil\n        case other                  => Seq(other)\n      }\n  },\n  Compile / compile / scalacOptions ~= {\n    _.filterNot(Set(\"-Ywarn-unused-import\", \"-Ywarn-unused:imports\"))\n  }\n)\n\nval root = project\n  .in(file(\".\"))\n  .enablePlugins(ScalaUnidocPlugin)\n  .settings(baseSettings ++ publishSettings)\n  .settings(\n    publish / skip := true,\n    mimaPreviousArtifacts := Set.empty,\n    console / initialCommands := \"import org.dhallj.parser.DhallParser.parse\",\n    releaseProcess := Seq[ReleaseStep](\n      checkSnapshotDependencies,\n      inquireVersions,\n      runClean,\n      releaseStepCommand(\"javacc\"),\n      runTest,\n      setReleaseVersion,\n      commitReleaseVersion,\n      tagRelease,\n      publishArtifacts,\n      setNextVersion,\n      commitNextVersion\n    )\n  )\n  .aggregate(\n    core,\n    parser,\n    javagen,\n    prelude,\n    cli,\n    ast,\n    scala,\n    codec,\n    circe,\n    jawn,\n    yaml,\n    cats,\n    imports,\n    importsMini,\n    testing,\n    tests,\n    benchmarks\n  )\n  .dependsOn(importsMini, scala, javagen, prelude, yaml)\n\nlazy val core = project\n  .in(file(\"modules/core\"))\n  .settings(baseSettings ++ javaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-core\",\n    name := \"dhall-core\",\n    description := \"DhallJ core\"\n  )\n\nlazy val parser = project\n  .in(file(\"modules/parser\"))\n  .settings(baseSettings ++ javaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-parser\",\n    name := \"dhall-parser\",\n    description := \"DhallJ parser\",\n    // Temporarily necessary because JavaCC produces invalid Javadocs.\n    Compile / javacOptions ++= Seq(\"-Xdoclint:none\")\n  )\n  .enablePlugins(JavaCCPlugin)\n  .dependsOn(core)\n\nlazy val prelude = project\n  .in(file(\"modules/prelude\"))\n  .settings(baseSettings ++ javaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-prelude\",\n    name := \"dhall-prelude\",\n    description := \"DhallJ Prelude\"\n  )\n  .dependsOn(core)\n\nlazy val cli = project\n  .in(file(\"cli\"))\n  .settings(baseSettings ++ javaSettings)\n  .settings(\n    publish / skip := true,\n    mimaPreviousArtifacts := Set.empty,\n    GraalVMNativeImage / name := \"dhall-cli\"\n  )\n  .enablePlugins(GraalVMNativeImagePlugin)\n  .dependsOn(parser, importsMini)\n\nlazy val circe = project\n  .in(file(\"modules/circe\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-circe\",\n    name := \"dhall-circe\",\n    description := \"DhallJ Circe integration\",\n    libraryDependencies ++= Seq(\n      \"io.circe\" %% \"circe-core\" % circeVersion,\n      \"io.circe\" %% \"circe-jawn\" % circeVersion % Test,\n      \"io.circe\" %% \"circe-testing\" % circeVersion % Test\n    )\n  )\n  .dependsOn(core, scala % Test)\n\nlazy val jawn = project\n  .in(file(\"modules/jawn\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-jawn\",\n    name := \"dhall-jawn\",\n    description := \"DhallJ Jawn integration\",\n    libraryDependencies ++= Seq(\n      \"io.circe\" %% \"circe-jawn\" % circeVersion % Test,\n      \"org.typelevel\" %% \"jawn-parser\" % jawnVersion\n    )\n  )\n  .dependsOn(core, scala % Test)\n\nlazy val yaml = project\n  .in(file(\"modules/yaml\"))\n  .settings(baseSettings ++ javaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-yaml\",\n    name := \"dhall-yaml\",\n    description := \"DhallJ YAML export\",\n    libraryDependencies += \"org.yaml\" % \"snakeyaml\" % snakeYamlVersion\n  )\n  .dependsOn(core, scala % Test)\n\nlazy val ast = project\n  .in(file(\"modules/ast\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(moduleName := \"dhall-ast\", name := \"dhall-ast\", description := \"DhallJ Scala AST\")\n  .dependsOn(importsMini)\n\nlazy val scala = project\n  .in(file(\"modules/scala\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(moduleName := \"dhall-scala\", name := \"dhall-scala\", description := \"DhallJ Scala wrapper\")\n  .dependsOn(ast, parser, importsMini)\n\nlazy val codec = project\n  .in(file(\"modules/scala-codec\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-scala-codec\",\n    name := \"dhall-scala-codec\",\n    description := \"DhallJ Scala encoding and decoding\",\n    libraryDependencies += \"org.typelevel\" %% \"cats-core\" % catsVersion\n  )\n  .dependsOn(scala)\n\nlazy val testing = project\n  .in(file(\"modules/testing\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-testing\",\n    name := \"dhall-testing\",\n    description := \"DhallJ ScalaCheck instances\",\n    libraryDependencies += \"org.scalacheck\" %% \"scalacheck\" % scalaCheckVersion\n  )\n  .dependsOn(ast)\n\nlazy val javagen = project\n  .in(file(\"modules/javagen\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-javagen\",\n    name := \"dhall-javagen\",\n    description := \"DhallJ Java code generation\"\n  )\n  .dependsOn(core)\n\nlazy val cats = project\n  .in(file(\"modules/cats\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(moduleName := \"dhall-cats\", name := \"dhall-cats\", description := \"DhallJ Cats integration\")\n  .settings(\n    libraryDependencies += \"org.typelevel\" %% \"cats-core\" % catsVersion\n  )\n  .dependsOn(core, testing % Test)\n\nlazy val imports = project\n  .in(file(\"modules/imports\"))\n  .settings(baseSettings ++ scalaSettings ++ publishSettings)\n  .settings(moduleName := \"dhall-imports\", name := \"dhall-imports\", description := \"DhallJ import resolution\")\n  .settings(\n    libraryDependencies ++= http4sDependencies :+ (http4sBlazeClient % Test)\n  )\n  .dependsOn(parser, cats)\n\nlazy val importsMini = project\n  .in(file(\"modules/imports-mini\"))\n  .settings(baseSettings ++ javaSettings ++ publishSettings)\n  .settings(\n    moduleName := \"dhall-imports-mini\",\n    name := \"dhall-imports-mini\",\n    description := \"DhallJ import resolution for Java\"\n  )\n  .dependsOn(parser, core)\n\nlazy val Slow = config(\"slow\").extend(Test)\n\nlazy val tests = project\n  .in(file(\"tests\"))\n  .configs(Slow)\n  .settings(baseSettings ++ scalaSettings)\n  .settings(\n    libraryDependencies ++= testDependencies,\n    libraryDependencies ++= http4sDependencies :+ http4sBlazeClient,\n    publish / skip := true,\n    mimaPreviousArtifacts := Set.empty,\n    Test / fork := true,\n    Test / baseDirectory := (ThisBuild / baseDirectory).value,\n    Test / testOptions += Tests.Argument(\"--exclude-tags=Slow\"),\n    Test / unmanagedResourceDirectories += (ThisBuild / baseDirectory).value / \"dhall-lang\",\n    inConfig(Slow)(Defaults.testTasks),\n    Slow / testOptions -= Tests.Argument(\"--exclude-tags=Slow\"),\n    Slow / testOptions += Tests.Argument(\"--include-tags=Slow\")\n  )\n  .dependsOn(scala, imports, importsMini, testing)\n\nlazy val benchmarks = project\n  .in(file(\"benchmarks\"))\n  .settings(baseSettings ++ scalaSettings)\n  .settings(\n    publish / skip := true,\n    mimaPreviousArtifacts := Set.empty\n  )\n  .enablePlugins(JmhPlugin)\n  .dependsOn(core, parser, prelude)\n\nlazy val publishSettings = Seq(\n  releaseCrossBuild := true,\n  releasePublishArtifactsAction := PgpKeys.publishSigned.value,\n  releaseVcsSign := true,\n  homepage := Some(url(\"https://github.com/travisbrown/dhallj\")),\n  licenses := Seq(\"BSD 3-Clause\" -> url(\"http://opensource.org/licenses/BSD-3-Clause\")),\n  publishMavenStyle := true,\n  Test / publishArtifact := false,\n  pomIncludeRepository := { _ => false },\n  publishTo := {\n    val nexus = \"https://oss.sonatype.org/\"\n    if (isSnapshot.value)\n      Some(\"snapshots\".at(nexus + \"content/repositories/snapshots\"))\n    else\n      Some(\"releases\".at(nexus + \"service/local/staging/deploy/maven2\"))\n  },\n  scmInfo := Some(\n    ScmInfo(\n      url(\"https://github.com/travisbrown/dhallj\"),\n      \"scm:git:git@github.com:travisbrown/dhallj.git\"\n    )\n  ),\n  pomExtra := (\n    <developers>\n      <developer>\n        <id>travisbrown</id>\n        <name>Travis Brown</name>\n        <email>travisrobertbrown@gmail.com</email>\n        <url>https://twitter.com/travisbrown</url>\n      </developer>\n      <developer>\n        <id>TimWSpence</id>\n        <name>Tim Spence</name>\n        <url>https://github.com/TimWSpence</url>\n      </developer>\n    </developers>\n  )\n)\n"
  },
  {
    "path": "cli/src/main/java/org/dhallj/cli/Dhall.java",
    "content": "package org.dhallj.cli;\n\nimport java.io.IOException;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.converters.JsonConverter;\nimport org.dhallj.imports.mini.Resolver;\nimport org.dhallj.parser.DhallParser;\n\npublic class Dhall {\n  public static void main(String[] args) throws IOException {\n    boolean resolveImports = false;\n    boolean typeCheck = false;\n    boolean normalize = false;\n    boolean alphaNormalize = false;\n\n    for (int i = 1; i < args.length; i++) {\n      if (args[i].equals(\"--resolve\")) {\n        resolveImports = true;\n      } else if (args[i].equals(\"--type-check\")) {\n        typeCheck = true;\n      } else if (args[i].equals(\"--normalize\")) {\n        normalize = true;\n      } else if (args[i].equals(\"--alpha\")) {\n        alphaNormalize = true;\n      }\n    }\n\n    Expr expr = DhallParser.parse(System.in);\n    Expr type = null;\n\n    if (resolveImports) {\n      expr = Resolver.resolve(expr, false);\n    }\n\n    if (normalize) {\n      expr = expr.normalize();\n    }\n\n    if (alphaNormalize) {\n      expr = expr.alphaNormalize();\n    }\n\n    if (typeCheck) {\n      type = Expr.Util.typeCheck(expr);\n    }\n\n    if (args.length == 0 || args[0].startsWith(\"--\")) {\n      System.out.println(expr);\n    } else if (args[0].equals(\"hash\")) {\n      System.out.printf(\"sha256:%s\\n\", expr.hash());\n    } else if (args[0].equals(\"type\")) {\n      if (!typeCheck) {\n        type = Expr.Util.typeCheck(expr);\n      }\n      System.out.println(type);\n    } else if (args[0].equals(\"json\")) {\n      System.out.println(JsonConverter.toCompactString(expr));\n    }\n  }\n}\n"
  },
  {
    "path": "javascript/BUILD",
    "content": "load(\"@com_google_j2cl//build_defs:rules.bzl\", \"j2cl_application\")\n\nj2cl_application(\n    name = \"dhall\",\n    closure_defines = {\"jre.classMetadata\": \"'STRIPPED'\"},\n    entry_points = [\"dhall.js\"],\n    jre_checks_check_level = \"MINIMAL\",\n    deps = [\"//javascript/api:dhall_js\"],\n)\n"
  },
  {
    "path": "javascript/api/BUILD",
    "content": "load(\"@io_bazel_rules_closure//closure:defs.bzl\", \"closure_js_library\")\nload(\"@com_google_j2cl//build_defs:rules.bzl\", \"j2cl_library\")\n\npackage(\n    default_visibility = [\"//visibility:public\"],\n)\n\nj2cl_library(\n    name = \"dhall_js_java\",\n    srcs = [\"DhallJs.java\"],\n    deps = [\n        \"//modules/core\",\n        \"//modules/parser\",\n    ],\n)\n\nclosure_js_library(\n    name = \"dhall_js\",\n    srcs = [\"dhall.js\"],\n    deps = [\":dhall_js_java\"],\n)\n"
  },
  {
    "path": "javascript/api/DhallJs.java",
    "content": "package org.dhallj.js;\n\nimport org.dhallj.core.Expr;\nimport org.dhallj.parser.DhallParser;\nimport jsinterop.annotations.JsType;\n\n@JsType\npublic class DhallJs {\n  public static String parse(String input) {\n    return DhallParser.parse(input).toString();\n  }\n\n  public static String normalize(String input) {\n    return DhallParser.parse(input).normalize().toString();\n  }\n\n  public static String typeCheck(String input) {\n    return Expr.Util.typeCheck(DhallParser.parse(input)).toString();\n  }\n}"
  },
  {
    "path": "javascript/api/dhall.js",
    "content": "goog.module('dhall.js');\n\nvar DhallJs = goog.require('org.dhallj.js.DhallJs');\n\n/**\n * @param {string} input\n * @return {null|string}\n */\nfunction parse(input) {\n  return DhallJs.parse(input);\n}\n\n/**\n * @param {string} input\n * @return {null|string}\n */\nfunction typeCheck(input) {\n  return DhallJs.typeCheck(input);\n}\n\n/**\n * @param {string} input\n * @return {null|string}\n */\nfunction normalize(input) {\n  return DhallJs.normalize(input);\n}\n\n// Otherwise we seem to lose stuff with some configurations?\nparse(\"1\");\ntypeCheck(\"1\");\nnormalize(\"1\");\n\ngoog.exportSymbol(\"parse\", parse);\ngoog.exportSymbol(\"typeCheck\", typeCheck);\ngoog.exportSymbol(\"normalize\", normalize);"
  },
  {
    "path": "javascript/jre/BUILD",
    "content": "load(\"@com_google_j2cl//build_defs:rules.bzl\", \"j2cl_library\")\n\npackage(\n    default_visibility = [\"//visibility:public\"],\n)\n\nj2cl_library(\n    name = \"java_io\",\n    srcs = [\n        \"BufferedReader.java\",\n        \"InputStreamReader.java\",\n    ],\n)\n\nj2cl_library(\n    name = \"java_net\",\n    srcs = [\n        \"URI.java\",\n        \"URISyntaxException.java\",\n    ],\n)\n\nj2cl_library(\n    name = \"java_nio_file\",\n    srcs = [\n        \"InvalidPathException.java\",\n        \"Path.java\",\n        \"Paths.java\",\n    ],\n)\n"
  },
  {
    "path": "javascript/jre/BufferedReader.java",
    "content": "package java.io;\n\npublic class BufferedReader extends Reader {\n  public BufferedReader(InputStreamReader stream) {}\n\n  public int read(char[] cbuf, int off, int len) {\n    return -1;\n  }\n\n  public void close() {}\n}\n"
  },
  {
    "path": "javascript/jre/InputStreamReader.java",
    "content": "package java.io;\n\npublic class InputStreamReader extends Reader {\n  public InputStreamReader(InputStream in) {}\n  public InputStreamReader(InputStream in, String charsetName) {}\n  public int read(char[] cbuf, int off, int len) {\n    return -1;\n  }\n\n  public void close() {}\n}\n"
  },
  {
    "path": "javascript/jre/InvalidPathException.java",
    "content": "package java.nio.file;\n\npublic class InvalidPathException extends IllegalArgumentException {}\n"
  },
  {
    "path": "javascript/jre/Path.java",
    "content": "package java.nio.file;\n\nimport java.util.Iterator;\n\npublic class Path {\n  private final String input;\n\n  public Path(String input) {\n    this.input = input;\n  }\n\n  public final boolean isAbsolute() {\n    return this.input.charAt(0) == '/';\n  }\n\n  public final Iterator<Path> iterator() {\n    return null;\n  }\n\n  public final int getNameCount() {\n    return 0;\n  }\n\n  public Path resolve(String other) {\n    return this;\n  }\n}\n"
  },
  {
    "path": "javascript/jre/Paths.java",
    "content": "package java.nio.file;\n\npublic class Paths {\n  /**\n   * @throws  InvalidPathException\n   *          if the path string cannot be converted to a {@code Path}\n   */\n  public static final Path get(String input) {\n    return new Path(input);\n  }\n}\n"
  },
  {
    "path": "javascript/jre/URI.java",
    "content": "package java.net;\n\npublic class URI {\n  private final String input;\n\n  public URI(String input) throws URISyntaxException {\n    this.input = input;\n  }\n\n  public final String getScheme() {\n    return \"\";\n  }\n\n  public final String getAuthority() {\n    return \"\";\n  }\n\n  public final String getPath() {\n    return \"\";\n  }\n\n  public final String getQuery() {\n    return \"\";\n  }\n}\n"
  },
  {
    "path": "javascript/jre/URISyntaxException.java",
    "content": "package java.net;\n\npublic class URISyntaxException extends Throwable {}\n"
  },
  {
    "path": "modules/ast/src/main/scala/org/dhallj/ast/package.scala",
    "content": "package org.dhallj.ast\n\nimport java.net.URI\nimport java.nio.file.Path\nimport java.lang.{Iterable => JIterable}\nimport java.math.BigInteger\nimport java.util.AbstractMap.SimpleImmutableEntry\nimport java.util.{Map => JMap}\nimport org.dhallj.core.{Expr, ExternalVisitor, Operator}\nimport scala.collection.JavaConverters._\n\nabstract private class OptionVisitor[A] extends ExternalVisitor.Constant[Option[A]](None)\n\nabstract private[ast] class Constructor[A] {\n  type Result = A\n\n  protected[this] def extractor: ExternalVisitor[Option[A]]\n\n  final def unapply(expr: Expr): Option[A] = expr.accept(extractor)\n\n  protected[this] def tupleToEntry[K, V](tuple: (K, V)): JMap.Entry[K, V] = new SimpleImmutableEntry(tuple._1, tuple._2)\n  protected[this] def optionTupleToEntry[K, V >: Null](tuple: (K, Option[V])): JMap.Entry[K, V] =\n    new SimpleImmutableEntry(tuple._1, tuple._2.orNull)\n\n  protected[this] def entryToTuple[K, V](entry: JMap.Entry[K, V]): (K, V) = (entry.getKey, entry.getValue)\n  protected[this] def entryToOptionTuple[K, V](entry: JMap.Entry[K, V]): (K, Option[V]) =\n    (entry.getKey, Option(entry.getValue))\n}\n\nobject NaturalLiteral extends Constructor[BigInt] {\n  def apply(value: BigInt): Option[Expr] =\n    if (value >= 0) Some(Expr.makeNaturalLiteral(value.underlying)) else None\n  def apply(value: Long): Option[Expr] =\n    if (value >= 0) Some(Expr.makeNaturalLiteral(BigInteger.valueOf(value))) else None\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onNatural(value: BigInteger): Option[BigInt] = Some(new BigInt(value))\n    }\n}\n\nobject IntegerLiteral extends Constructor[BigInt] {\n  def apply(value: BigInt): Expr = Expr.makeIntegerLiteral(value.underlying)\n  def apply(value: Long): Expr = Expr.makeNaturalLiteral(BigInteger.valueOf(value))\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onInteger(value: BigInteger): Option[BigInt] = Some(new BigInt(value))\n    }\n}\n\nobject DoubleLiteral extends Constructor[Double] {\n  def apply(value: Double): Expr = Expr.makeDoubleLiteral(value)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] = new OptionVisitor[Result] {\n    override def onDouble(value: Double): Option[Double] = Some(value)\n  }\n}\n\nobject BoolLiteral extends Constructor[Boolean] {\n  def apply(value: Boolean): Expr = if (value) Expr.Constants.TRUE else Expr.Constants.FALSE\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] = new OptionVisitor[Result] {\n    override def onBuiltIn(name: String): Option[Boolean] = name match {\n      case \"True\"  => Some(true)\n      case \"False\" => Some(false)\n      case _       => None\n    }\n  }\n}\n\nobject Identifier extends Constructor[(String, Option[Long])] {\n  def apply(name: String, index: Long): Expr = Expr.makeIdentifier(name, index)\n  def apply(name: String): Expr = apply(name, 0)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onIdentifier(name: String, index: Long): Option[Result] =\n        Some((name, if (index == 0) None else Some(index)))\n    }\n}\n\nobject Lambda extends Constructor[(String, Expr, Expr)] {\n  def apply(name: String, tpe: Expr, result: Expr): Expr = Expr.makeLambda(name, tpe, result)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onLambda(name: String, tpe: Expr, result: Expr): Option[Result] =\n        Some((name, tpe, result))\n    }\n}\n\nobject Pi extends Constructor[(Option[String], Expr, Expr)] {\n  def apply(name: String, tpe: Expr, result: Expr): Expr = Expr.makePi(name, tpe, result)\n  def apply(tpe: Expr, result: Expr): Expr = Expr.makePi(\"_\", tpe, result)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onPi(name: String, tpe: Expr, result: Expr): Option[Result] =\n        Some((if (name == \"_\") None else Some(name), tpe, result))\n    }\n}\n\nobject Let extends Constructor[(String, Option[Expr], Expr, Expr)] {\n  def apply(name: String, tpe: Expr, value: Expr, body: Expr): Expr = Expr.makeLet(name, tpe, value, body)\n  def apply(name: String, value: Expr, body: Expr): Expr = Expr.makeLet(name, null, value, body)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onLet(name: String, tpe: Expr, value: Expr, body: Expr): Option[Result] =\n        Some(name, Option(tpe), value, body)\n    }\n}\n\nobject TextLiteral extends Constructor[(String, Vector[(Expr, String)])] {\n  def apply(value: String): Expr = Expr.makeTextLiteral(value)\n  def apply(first: String, rest: Vector[(Expr, String)]): Expr = {\n    val parts = first +: rest.map(_._2).toArray\n    val interpolated = rest.map(_._1).toArray\n\n    Expr.makeTextLiteral(parts, interpolated)\n  }\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onText(parts: Array[String], interpolated: JIterable[Expr]): Option[Result] =\n        Some((parts(0), interpolated.asScala.zip(parts.tail).toVector))\n    }\n}\n\nobject NonEmptyListLiteral extends Constructor[Vector[Expr]] {\n  def apply(head: Expr, tail: Vector[Expr]): Expr = Expr.makeNonEmptyListLiteral((head +: tail).asJava)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onNonEmptyList(values: JIterable[Expr], size: Int): Option[Vector[Expr]] =\n        Some(values.asScala.toVector)\n    }\n}\n\nobject EmptyListLiteral extends Constructor[Expr] {\n  def apply(tpe: Expr): Expr = Expr.makeEmptyListLiteral(tpe)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onEmptyList(tpe: Expr): Option[Expr] = Some(tpe)\n    }\n}\n\nobject ListLiteral extends Constructor[Vector[Expr]] {\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onNonEmptyList(values: JIterable[Expr], size: Int): Option[Vector[Expr]] =\n        Some(values.asScala.toVector)\n      override def onEmptyList(tpe: Expr): Option[Vector[Expr]] = Some(Vector.empty)\n    }\n}\n\nobject RecordLiteral extends Constructor[Map[String, Expr]] {\n  def apply(fields: Map[String, Expr]): Expr = Expr.makeRecordLiteral(fields.toSeq.map(tupleToEntry).asJava)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onRecord(fields: JIterable[JMap.Entry[String, Expr]], size: Int): Option[Map[String, Expr]] =\n        Some(fields.asScala.map(entryToTuple).toMap)\n    }\n}\n\nobject RecordType extends Constructor[Map[String, Expr]] {\n  def apply(fields: Map[String, Expr]): Expr = Expr.makeRecordType(fields.toSeq.map(tupleToEntry).asJava)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onRecordType(fields: JIterable[JMap.Entry[String, Expr]], size: Int): Option[Map[String, Expr]] =\n        Some(fields.asScala.map(entryToTuple).toMap)\n    }\n}\n\nobject UnionType extends Constructor[Map[String, Option[Expr]]] {\n  def apply(fields: Map[String, Option[Expr]]): Expr = Expr.makeUnionType(fields.toSeq.map(optionTupleToEntry).asJava)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onUnionType(fields: JIterable[JMap.Entry[String, Expr]],\n                               size: Int\n      ): Option[Map[String, Option[Expr]]] =\n        Some(fields.asScala.map(entryToOptionTuple).toMap)\n    }\n}\n\nobject FieldAccess extends Constructor[(Expr, String)] {\n  def apply(base: Expr, fieldName: String): Expr = Expr.makeFieldAccess(base, fieldName)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onFieldAccess(base: Expr, fieldName: String): Option[Result] = Some((base, fieldName))\n    }\n}\n\nobject Projection extends Constructor[(Expr, Vector[String])] {\n  def apply(base: Expr, fieldNames: Vector[String]): Expr = Expr.makeProjection(base, fieldNames.toArray)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onProjection(base: Expr, fieldNames: Array[String]): Option[Result] =\n        Some(base, fieldNames.toVector)\n    }\n}\n\nobject ProjectionByType extends Constructor[(Expr, Expr)] {\n  def apply(base: Expr, tpe: Expr): Expr = Expr.makeProjectionByType(base, tpe)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onProjectionByType(base: Expr, tpe: Expr): Option[Result] =\n        Some(base, tpe)\n    }\n}\n\nobject Application extends Constructor[(Expr, Expr)] {\n  def apply(base: Expr, arg: Expr): Expr = Expr.makeApplication(base, arg)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onApplication(base: Expr, arg: Expr): Option[Result] =\n        Some((base, arg))\n    }\n}\n\nobject OperatorApplication extends Constructor[(Operator, Expr, Expr)] {\n  def apply(operator: Operator, lhs: Expr, rhs: Expr): Expr = Expr.makeOperatorApplication(operator, lhs, rhs)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onOperatorApplication(operator: Operator, lhs: Expr, rhs: Expr): Option[Result] =\n        Some((operator, lhs, rhs))\n    }\n}\n\nobject If extends Constructor[(Expr, Expr, Expr)] {\n  def apply(cond: Expr, thenValue: Expr, elseValue: Expr): Expr = Expr.makeIf(cond, thenValue, elseValue)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onIf(cond: Expr, thenValue: Expr, elseValue: Expr): Option[Result] =\n        Some((cond, thenValue, elseValue))\n    }\n}\n\nobject Annotated extends Constructor[(Expr, Expr)] {\n  def apply(base: Expr, tpe: Expr): Expr = Expr.makeAnnotated(base, tpe)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onAnnotated(base: Expr, tpe: Expr): Option[Result] =\n        Some((base, tpe))\n    }\n}\n\nobject Assert extends Constructor[Expr] {\n  def apply(base: Expr): Expr = Expr.makeAssert(base)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onAssert(base: Expr): Option[Expr] =\n        Some(base)\n    }\n}\n\nobject Merge extends Constructor[(Expr, Expr, Option[Expr])] {\n  def apply(handlers: Expr, union: Expr, tpe: Expr): Expr = Expr.makeMerge(handlers, union, tpe)\n  def apply(handlers: Expr, union: Expr): Expr = Expr.makeMerge(handlers, union, null)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onMerge(handlers: Expr, union: Expr, tpe: Expr): Option[Result] =\n        Some(handlers, union, Option(tpe))\n    }\n}\n\nobject ToMap extends Constructor[(Expr, Option[Expr])] {\n  def apply(base: Expr, tpe: Expr): Expr = Expr.makeToMap(base, tpe)\n  def apply(base: Expr): Expr = Expr.makeToMap(base, null)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onToMap(base: Expr, tpe: Expr): Option[Result] = Some(base, Option(tpe))\n    }\n}\n\nobject MissingImport extends Constructor[(Expr.ImportMode, Option[String])] {\n\n  /**\n   * Note that this constructor does not verify that the input is a hex-encoded SHA-256 hash.\n   */\n  def apply(mode: Expr.ImportMode, hash: String): Expr = Expr.makeMissingImport(mode, Expr.Util.decodeHashBytes(hash))\n  def apply(mode: Expr.ImportMode): Expr = Expr.makeMissingImport(mode, null)\n  def apply(): Expr = Expr.makeMissingImport(Expr.ImportMode.CODE, null)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onMissingImport(mode: Expr.ImportMode, hash: Array[Byte]): Option[Result] =\n        Some((mode, Option(hash).map(Expr.Util.encodeHashBytes)))\n    }\n}\n\nobject EnvImport extends Constructor[(String, Expr.ImportMode, Option[String])] {\n\n  /**\n   * Note that this constructor does not verify that the input is a hex-encoded SHA-256 hash.\n   */\n  def apply(name: String, mode: Expr.ImportMode, hash: String): Expr =\n    Expr.makeEnvImport(name, mode, Expr.Util.decodeHashBytes(hash))\n  def apply(name: String, mode: Expr.ImportMode): Expr = Expr.makeEnvImport(name, mode, null)\n  def apply(name: String): Expr = Expr.makeEnvImport(name, Expr.ImportMode.CODE, null)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onEnvImport(name: String, mode: Expr.ImportMode, hash: Array[Byte]): Option[Result] =\n        Some((name, mode, Option(hash).map(Expr.Util.encodeHashBytes)))\n    }\n}\n\nobject LocalImport extends Constructor[(Path, Expr.ImportMode, Option[String])] {\n\n  /**\n   * Note that this constructor does not verify that the input is a hex-encoded SHA-256 hash.\n   */\n  def apply(path: Path, mode: Expr.ImportMode, hash: String): Expr =\n    Expr.makeLocalImport(path, mode, Expr.Util.decodeHashBytes(hash))\n  def apply(path: Path, mode: Expr.ImportMode): Expr = Expr.makeLocalImport(path, mode, null)\n  def apply(path: Path): Expr = Expr.makeLocalImport(path, Expr.ImportMode.CODE, null)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onLocalImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): Option[Result] =\n        Some((path, mode, Option(hash).map(Expr.Util.encodeHashBytes)))\n    }\n}\n\nobject RemoteImport extends Constructor[(URI, Option[Expr], Expr.ImportMode, Option[String])] {\n\n  /**\n   * Note that this constructor does not verify that the input is a hex-encoded SHA-256 hash.\n   */\n  def apply(url: URI, usingExpr: Expr, mode: Expr.ImportMode, hash: String): Expr =\n    Expr.makeRemoteImport(url, usingExpr, mode, Expr.Util.decodeHashBytes(hash))\n  def apply(url: URI, usingExpr: Expr, mode: Expr.ImportMode): Expr = Expr.makeRemoteImport(url, usingExpr, mode, null)\n  def apply(url: URI, usingExpr: Expr): Expr = Expr.makeRemoteImport(url, usingExpr, Expr.ImportMode.CODE, null)\n  def apply(url: URI): Expr = Expr.makeRemoteImport(url, null, Expr.ImportMode.CODE, null)\n\n  protected[this] val extractor: ExternalVisitor[Option[Result]] =\n    new OptionVisitor[Result] {\n      override def onRemoteImport(url: URI, usingExpr: Expr, mode: Expr.ImportMode, hash: Array[Byte]): Option[Result] =\n        Some((url, Option(usingExpr), mode, Option(hash).map(Expr.Util.encodeHashBytes)))\n    }\n}\n"
  },
  {
    "path": "modules/cats/src/main/scala/org/dhallj/cats/LiftVisitor.scala",
    "content": "package org.dhallj.cats\n\nimport cats.Applicative\nimport java.math.BigDecimal\nimport java.math.BigInteger\nimport java.net.URI\nimport java.nio.file.Path\nimport java.util.AbstractMap.SimpleImmutableEntry\nimport java.util.ArrayList\nimport java.util.{List => JList, Map => JMap}\nimport org.dhallj.core.{Expr, Operator, Source, Visitor}\n\n/**\n * Represents a function lifting an `Expr` into an `F[Expr]`.\n *\n * This is a convenience class designed to help with implementations that don't need effects for most cases.\n */\nclass LiftVisitor[F[_] <: AnyRef](\n  private[this] val F: Applicative[F],\n  private[this] val sortFields: Boolean = false\n) extends Visitor.NoPrepareEvents[F[Expr]] {\n  def onNote(base: F[Expr], source: Source): F[Expr] = base\n  def onNatural(self: Expr, value: BigInteger): F[Expr] = F.pure(self)\n  def onInteger(self: Expr, value: BigInteger): F[Expr] = F.pure(self)\n  def onDouble(self: Expr, value: Double): F[Expr] = F.pure(self)\n  def onDate(self: Expr, year: Int, month: Int, day: Int): F[Expr] = F.pure(self)\n  def onTime(self: Expr, hour: Int, minute: Int, second: Int, fractional: BigDecimal): F[Expr] = F.pure(self)\n  def onTimeZone(self: Expr, seconds: Int): F[Expr] = F.pure(self)\n  def onBuiltIn(self: Expr, name: String): F[Expr] = F.pure(self)\n  def onIdentifier(self: Expr, value: String, index: Long): F[Expr] = F.pure(self)\n\n  def onLambda(name: String, tpe: F[Expr], result: F[Expr]): F[Expr] =\n    F.map2(tpe, result)(Expr.makeLambda(name, _, _))\n\n  def onPi(name: String, tpe: F[Expr], result: F[Expr]): F[Expr] =\n    F.map2(tpe, result)(Expr.makePi(name, _, _))\n\n  def onLet(bindings: JList[Expr.LetBinding[F[Expr]]], body: F[Expr]): F[Expr] =\n    F.map2(sequenceBindings(bindings), body)(Expr.makeLet(_, _))\n\n  def onText(parts: Array[String], interpolated: JList[F[Expr]]): F[Expr] =\n    F.map(sequenceValues(interpolated))(Expr.makeTextLiteral(parts, _))\n\n  def onNonEmptyList(values: JList[F[Expr]]): F[Expr] =\n    F.map(sequenceValues(values))(Expr.makeNonEmptyListLiteral(_))\n\n  def onEmptyList(tpe: F[Expr]): F[Expr] = F.map(tpe)(Expr.makeEmptyListLiteral(_))\n\n  def onRecord(fields: JList[JMap.Entry[String, F[Expr]]]): F[Expr] =\n    F.map(sequenceFields(fields, false, sortFields))(Expr.makeRecordLiteral(_))\n\n  def onRecordType(fields: JList[JMap.Entry[String, F[Expr]]]): F[Expr] =\n    F.map(sequenceFields(fields, false, sortFields))(Expr.makeRecordType(_))\n\n  def onUnionType(fields: JList[JMap.Entry[String, F[Expr]]]): F[Expr] =\n    F.map(sequenceFields(fields, true, sortFields))(Expr.makeUnionType(_))\n\n  def onFieldAccess(base: F[Expr], fieldName: String): F[Expr] =\n    F.map(base)(Expr.makeFieldAccess(_, fieldName))\n\n  def onProjection(base: F[Expr], fieldNames: Array[String]): F[Expr] =\n    F.map(base)(Expr.makeProjection(_, fieldNames))\n\n  def onProjectionByType(base: F[Expr], tpe: F[Expr]): F[Expr] =\n    F.map2(base, tpe)(Expr.makeProjectionByType(_, _))\n\n  def onApplication(base: F[Expr], args: JList[F[Expr]]): F[Expr] =\n    F.map2(base, sequenceValues(args))(Expr.makeApplication(_, _))\n\n  def onOperatorApplication(operator: Operator, lhs: F[Expr], rhs: F[Expr]): F[Expr] =\n    F.map2(lhs, rhs)(Expr.makeOperatorApplication(operator, _, _))\n\n  def onIf(predicate: F[Expr], thenValue: F[Expr], elseValue: F[Expr]): F[Expr] =\n    F.map3(predicate, thenValue, elseValue)(Expr.makeIf(_, _, _))\n\n  def onAnnotated(base: F[Expr], tpe: F[Expr]): F[Expr] =\n    F.map2(base, tpe)(Expr.makeAnnotated(_, _))\n\n  def onAssert(base: F[Expr]): F[Expr] = F.map(base)(Expr.makeAssert(_))\n\n  def onMerge(handlers: F[Expr], union: F[Expr], tpe: F[Expr]): F[Expr] =\n    if (tpe.eq(null)) {\n      F.map2(handlers, union)(Expr.makeMerge(_, _, null))\n    } else {\n      F.map3(handlers, union, tpe)(Expr.makeMerge(_, _, _))\n    }\n\n  def onToMap(base: F[Expr], tpe: F[Expr]): F[Expr] =\n    if (tpe.eq(null)) {\n      F.map(base)(Expr.makeToMap(_, null))\n    } else {\n      F.map2(base, tpe)(Expr.makeToMap(_, _))\n    }\n\n  def onWith(base: F[Expr], path: Array[String], value: F[Expr]): F[Expr] =\n    F.map2(base, value)(Expr.makeWith(_, path, _))\n\n  def onMissingImport(mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    F.pure(Expr.makeMissingImport(mode, hash))\n\n  def onEnvImport(name: String, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    F.pure(Expr.makeEnvImport(name, mode, hash))\n\n  def onLocalImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    F.pure(Expr.makeLocalImport(path, mode, hash))\n\n  def onClasspathImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    F.pure(Expr.makeClasspathImport(path, mode, hash))\n\n  def onRemoteImport(url: URI, headers: F[Expr], mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    if (headers.eq(null)) {\n      F.pure(Expr.makeRemoteImport(url, null, mode, hash))\n    } else {\n      F.map(headers)(Expr.makeRemoteImport(url, _, mode, hash))\n    }\n\n  final private[this] def sequenceValues(values: JList[F[Expr]]): F[Array[Expr]] = {\n    var result = F.pure(new Array[Expr](values.size))\n    var i = 0\n\n    while (i < values.size) {\n      val index = i\n      result = F.map2(result, values.get(index)) { case (acc, next) =>\n        acc(index) = next\n        acc\n      }\n      i += 1\n    }\n\n    result\n  }\n\n  final private[this] def sequenceFields(\n    fields: JList[JMap.Entry[String, F[Expr]]],\n    checkNull: Boolean,\n    sortFields: Boolean\n  ): F[Array[JMap.Entry[String, Expr]]] = {\n    var result = F.pure(new Array[JMap.Entry[String, Expr]](fields.size))\n    var i = 0\n\n    while (i < fields.size) {\n      val index = i\n      val entry = fields.get(index)\n      val fieldName = entry.getKey\n      val value = entry.getValue\n\n      if (checkNull && value.eq(null)) {\n        result = F.map(result) { acc =>\n          acc(index) = new SimpleImmutableEntry(fieldName, null)\n          acc\n        }\n      } else {\n        result = F.map2(result, value) { case (acc, nextValue) =>\n          acc(index) = new SimpleImmutableEntry(fieldName, nextValue)\n          acc\n        }\n      }\n\n      i += 1\n    }\n\n    if (sortFields) {\n      F.map(result)(_.sortBy(_.getKey))\n    } else {\n      result\n    }\n  }\n\n  final private[this] def sequenceBindings(\n    bindings: JList[Expr.LetBinding[F[Expr]]]\n  ): F[JList[Expr.LetBinding[Expr]]] = {\n    var result: F[JList[Expr.LetBinding[Expr]]] =\n      F.pure(new ArrayList[Expr.LetBinding[Expr]](bindings.size))\n    var i = 0\n\n    while (i < bindings.size) {\n      val index = i\n      val binding = bindings.get(index)\n\n      if (binding.hasType) {\n        result = F.map3(result, binding.getType, binding.getValue) { case (acc, nextType, nextValue) =>\n          acc.add(new Expr.LetBinding(binding.getName, nextType, nextValue))\n          acc\n        }\n      } else {\n        result = F.map2(result, binding.getValue) { case (acc, nextValue) =>\n          acc.add(new Expr.LetBinding(binding.getName, null, nextValue))\n          acc\n        }\n      }\n\n      i += 1\n    }\n\n    result\n  }\n}\n"
  },
  {
    "path": "modules/cats/src/test/scala/org/dhallj/cats/LiftVisitorSuite.scala",
    "content": "package org.dhallj.cats\n\nimport cats.Applicative\nimport cats.instances.option._\nimport munit.ScalaCheckSuite\nimport org.dhallj.core.Expr\nimport org.dhallj.testing.instances._\nimport org.scalacheck.Prop\n\nclass LiftVisitorSuite extends ScalaCheckSuite {\n  property(\"LiftVisitor with no overrides is pure\") {\n    Prop.forAll { (expr: Expr) =>\n      val lift = new LiftVisitor[Option](Applicative[Option])\n\n      expr.accept(lift) == Some(expr)\n    }\n  }\n}\n"
  },
  {
    "path": "modules/circe/src/main/scala/org/dhallj/circe/CirceHandler.scala",
    "content": "package org.dhallj.circe\n\nimport io.circe.Json\nimport java.math.BigInteger\nimport java.util.{ArrayDeque, ArrayList, Deque, LinkedHashMap, List}\nimport org.dhallj.core.converters.JsonHandler\nimport scala.collection.JavaConverters._\n\nsealed private trait Context {\n  def add(key: String): Unit\n  def add(value: Json): Unit\n  def result: Json\n}\n\nfinal private class RootContext(value: Json) extends Context {\n  def add(key: String): Unit = ()\n  def add(value: Json): Unit = ()\n  def result: Json = value\n}\n\nfinal private class ObjectContext() extends Context {\n  private[this] var key: String = null\n  private[this] val fields: LinkedHashMap[String, Json] = new LinkedHashMap()\n\n  def add(key: String): Unit = this.key = key\n  def add(value: Json): Unit = this.fields.put(this.key, value)\n  def result: Json = Json.fromFields(this.fields.entrySet.asScala.map(entry => entry.getKey -> entry.getValue))\n}\n\nfinal private class ArrayContext() extends Context {\n  private[this] val values: List[Json] = new ArrayList()\n\n  def add(key: String): Unit = ()\n  def add(value: Json): Unit = this.values.add(value)\n  def result: Json = Json.fromValues(this.values.asScala)\n}\n\nclass CirceHandler extends JsonHandler {\n  private[this] val stack: Deque[Context] = new ArrayDeque()\n\n  protected[this] def addValue(value: Json): Unit =\n    if (stack.isEmpty) {\n      stack.push(new RootContext(value))\n    } else {\n      stack.peek.add(value)\n    }\n\n  final def result: Json = stack.pop().result\n\n  final def onNull(): Unit = addValue(Json.Null)\n  final def onBoolean(value: Boolean): Unit = addValue(if (value) Json.True else Json.False)\n  final def onNumber(value: BigInteger): Unit = addValue(Json.fromBigInt(new BigInt(value)))\n  def onDouble(value: Double): Unit = addValue(Json.fromDoubleOrNull(value))\n  final def onString(value: String): Unit = addValue(Json.fromString(value))\n\n  final def onArrayStart(): Unit = stack.push(new ArrayContext())\n\n  final def onArrayEnd(): Unit = {\n    val current = stack.pop()\n\n    if (stack.isEmpty) {\n      stack.push(current)\n    } else {\n      stack.peek.add(current.result)\n    }\n  }\n\n  final def onArrayElementGap(): Unit = ()\n\n  final def onObjectStart(): Unit = stack.push(new ObjectContext())\n\n  final def onObjectEnd(): Unit = {\n    val current = stack.pop()\n\n    if (stack.isEmpty) {\n      stack.push(current)\n    } else {\n      stack.peek.add(current.result)\n    }\n  }\n\n  final def onObjectField(name: String): Unit = stack.peek.add(name)\n\n  final def onObjectFieldGap(): Unit = ()\n}\n"
  },
  {
    "path": "modules/circe/src/main/scala/org/dhallj/circe/Converter.scala",
    "content": "package org.dhallj.circe\n\nimport io.circe.{Json, JsonNumber, JsonObject}\nimport java.math.BigInteger\nimport java.util.AbstractMap.SimpleImmutableEntry\nimport java.util.Map.Entry\nimport org.dhallj.core.Expr\nimport org.dhallj.core.converters.JsonConverter\n\nobject Converter {\n  def apply(expr: Expr): Option[Json] = {\n    val handler = new CirceHandler()\n    val wasConverted = expr.accept(new JsonConverter(handler, false))\n\n    if (wasConverted) Some(handler.result) else None\n  }\n\n  private[this] val folder: Json.Folder[Expr] = new Json.Folder[Expr] {\n    def onBoolean(value: Boolean): Expr = if (value) Expr.Constants.TRUE else Expr.Constants.FALSE\n    def onNull: Expr = Expr.makeApplication(Expr.Constants.NONE, Expr.Constants.EMPTY_RECORD_TYPE)\n    def onNumber(value: JsonNumber): Expr = {\n      val asDouble = value.toDouble\n\n      if (java.lang.Double.compare(asDouble, -0.0) == 0) {\n        Expr.makeDoubleLiteral(asDouble)\n      } else\n        value.toBigInt match {\n          case Some(integer) =>\n            if (integer.underlying.compareTo(BigInteger.ZERO) > 0) {\n              Expr.makeNaturalLiteral(integer.underlying)\n            } else {\n              Expr.makeIntegerLiteral(integer.underlying)\n            }\n          case None => Expr.makeDoubleLiteral(asDouble)\n        }\n    }\n    def onString(value: String): Expr = Expr.makeTextLiteral(value)\n    def onObject(value: JsonObject): Expr = Expr.makeRecordLiteral(\n      value.toMap.map { case (k, v) =>\n        new SimpleImmutableEntry(k, v.foldWith(this)): Entry[String, Expr]\n      }.toArray\n    )\n    def onArray(value: Vector[Json]): Expr =\n      if (value.isEmpty) {\n        Expr.makeEmptyListLiteral(Expr.makeApplication(Expr.Constants.LIST, Expr.Constants.EMPTY_RECORD_TYPE))\n      } else {\n        Expr.makeNonEmptyListLiteral(value.map(_.foldWith(this)).toArray)\n      }\n  }\n\n  def apply(json: Json): Expr = json.foldWith(folder)\n}\n"
  },
  {
    "path": "modules/circe/src/test/scala/org/dhallj/circe/CirceConverterSuite.scala",
    "content": "package org.dhallj.circe\n\nimport io.circe.Json\nimport io.circe.syntax._\nimport io.circe.testing.instances._\nimport munit.ScalaCheckSuite\nimport org.dhallj.ast._\nimport org.dhallj.core.Expr\nimport org.dhallj.parser.DhallParser\nimport org.scalacheck.Prop\n\nclass CirceConverterSuite extends ScalaCheckSuite {\n  property(\"round-trip Json values through Dhall expressions\") {\n    Prop.forAll { (value: Json) =>\n      val cleanedJson = value.foldWith(JsonCleaner)\n      val asDhall = Converter(cleanedJson)\n      Converter(asDhall) == Some(cleanedJson)\n    }\n  }\n\n  property(\"convert integers\") {\n    Prop.forAll { (value: BigInt) =>\n      val asDhall = IntegerLiteral(value.underlying)\n      Converter(asDhall) == Some(value.asJson)\n    }\n  }\n\n  property(\"convert lists of integers\") {\n    Prop.forAll { (values: Vector[BigInt]) =>\n      val asDhall = if (values.isEmpty) {\n        EmptyListLiteral(Expr.Constants.INTEGER)\n      } else {\n        val exprs = values.map(value => IntegerLiteral(value.underlying))\n        NonEmptyListLiteral(exprs.head, exprs.tail)\n      }\n      Converter(asDhall) == Some(values.asJson)\n    }\n  }\n\n  property(\"convert lists of doubles\") {\n    Prop.forAll { (values: Vector[Double]) =>\n      val asDhall = if (values.isEmpty) {\n        EmptyListLiteral(Expr.Constants.DOUBLE)\n      } else {\n        val exprs = values.map(DoubleLiteral(_))\n        NonEmptyListLiteral(exprs.head, exprs.tail)\n      }\n      Converter(asDhall) == Some(values.asJson)\n    }\n  }\n\n  property(\"convert lists of booleans\") {\n    Prop.forAll { (values: Vector[Boolean]) =>\n      val asDhall = if (values.isEmpty) {\n        EmptyListLiteral(Expr.Constants.BOOL)\n      } else {\n        val exprs = values.map(BoolLiteral(_))\n        NonEmptyListLiteral(exprs.head, exprs.tail)\n      }\n      Converter(asDhall) == Some(values.asJson)\n    }\n  }\n\n  test(\"convert nested lists\") {\n    val expr = DhallParser.parse(\"[[]: List Bool]\")\n\n    assert(Converter(expr) == Some(Json.arr(Json.arr())))\n  }\n\n  test(\"convert None\") {\n    val expr = DhallParser.parse(\"None Bool\")\n\n    assert(Converter(expr) == Some(Json.Null))\n  }\n\n  test(\"convert Some\") {\n    val expr = DhallParser.parse(\"\"\"Some \"foo\"\"\"\")\n\n    assert(Converter(expr) == Some(Json.fromString(\"foo\")))\n  }\n\n  test(\"convert records\") {\n    val expr1 = DhallParser.parse(\"{foo = [{bar = [1]}, {bar = [1, 2, 3]}]}\")\n    val Right(json1) = io.circe.jawn.parse(\"\"\"{\"foo\": [{\"bar\": [1]}, {\"bar\": [1, 2, 3]}]}\"\"\")\n\n    assert(Converter(expr1) == Some(json1))\n  }\n\n  test(\"convert unions (nullary constructors)\") {\n    val expr1 = DhallParser.parse(\"[((\\\\(x: Natural) -> <foo: Bool|bar>) 1).bar]\").normalize()\n    val Right(json1) = io.circe.jawn.parse(\"\"\"[\"bar\"]\"\"\")\n\n    assert(Converter(expr1) == Some(json1))\n  }\n\n  test(\"convert unions\") {\n    val expr1 = DhallParser.parse(\"[<foo: Bool|bar>.foo True]\").normalize()\n    val Right(json1) = io.circe.jawn.parse(\"\"\"[true]\"\"\")\n\n    assert(Converter(expr1) == Some(json1))\n  }\n\n  test(\"fail safely on unconvertible expressions\") {\n    val expr1 = Lambda(\"x\", Expr.Constants.NATURAL, Identifier(\"x\"))\n\n    assert(Converter(expr1) == None)\n  }\n}\n"
  },
  {
    "path": "modules/circe/src/test/scala/org/dhallj/circe/JsonCleaner.scala",
    "content": "package org.dhallj.circe\n\nimport io.circe.{Json, JsonNumber, JsonObject}\n\nobject JsonCleaner extends Json.Folder[Json] {\n  def onBoolean(value: Boolean): Json = Json.fromBoolean(value)\n  def onNull: Json = Json.Null\n  def onNumber(value: JsonNumber): Json = {\n    val asDouble = value.toDouble\n    val asJson = Json.fromDoubleOrNull(asDouble)\n    if (asJson.asNumber == Some(value)) {\n      asJson\n    } else {\n      Json.fromLong(0)\n    }\n  }\n  def onString(value: String): Json = Json.fromString(value)\n  def onObject(value: JsonObject): Json = Json.fromFields(\n    value.toIterable.flatMap {\n      case (\"\", v) => None\n      case (k, v)  => Some((k, v.foldWith(this)))\n    }\n  )\n  def onArray(values: Vector[Json]): Json = Json.fromValues(values.map(_.foldWith(this)))\n}\n"
  },
  {
    "path": "modules/core/BUILD",
    "content": "load(\"@com_google_j2cl//build_defs:rules.bzl\", \"j2cl_library\")\n\npackage(\n    default_visibility = [\"//visibility:public\"],\n)\n\nj2cl_library(\n    name = \"cbor\",\n    srcs = glob([\n        \"src/main/java/org/dhallj/cbor/*.java\",\n    ]),\n)\n\nj2cl_library(\n    name = \"core\",\n    srcs = glob([\n        \"src/main/java/org/dhallj/core/*.java\",\n        \"src/main/java/org/dhallj/core/binary/*.java\",\n        \"src/main/java/org/dhallj/core/normalization/*.java\",\n        \"src/main/java/org/dhallj/core/typechecking/*.java\",\n    ]),\n    deps = [\n        \":cbor\",\n        \"//javascript/jre:java_net\",\n        \"//javascript/jre:java_nio_file\",\n    ],\n)\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/AdditionalInfo.java",
    "content": "package org.dhallj.cbor;\n\npublic enum AdditionalInfo {\n  DIRECT(0), // 0-23\n  ONE_BYTE(24), // 24\n  TWO_BYTES(25), // 25\n  FOUR_BYTES(26), // 26\n  EIGHT_BYTES(27), // 27\n  RESERVED(28), // 28-30\n  INDEFINITE(31); // 31\n\n  final int value;\n\n  private AdditionalInfo(int value) {\n    this.value = value;\n  }\n\n  public static AdditionalInfo fromByte(byte b) {\n    switch (b & 31) {\n      case 24:\n        return ONE_BYTE;\n      case 25:\n        return TWO_BYTES;\n      case 26:\n        return FOUR_BYTES;\n      case 27:\n        return EIGHT_BYTES;\n      case 28:\n      case 29:\n      case 30:\n        return RESERVED;\n      case 31:\n        return INDEFINITE;\n      default:\n        return DIRECT;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/CborException.java",
    "content": "package org.dhallj.cbor;\n\npublic class CborException extends RuntimeException {\n  CborException(String message) {\n    super(message);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/HalfFloat.java",
    "content": "package org.dhallj.cbor;\n\n/**\n * Conversions between 16 and 32-bit floating point numbers.\n *\n * @see <a href=\"https://stackoverflow.com/a/6162687/334519\">this Stack Overflow answer</a>\n */\npublic final class HalfFloat {\n  public static final int fromFloat(float asFloat) {\n    int bits = Float.floatToIntBits(asFloat);\n    int sign = bits >>> 16 & 0x8000; // sign only\n    int value = (bits & 0x7fffffff) + 0x1000; // rounded value\n\n    if (value >= 0x47800000) // might be or become NaN/Inf\n    { // avoid Inf due to rounding\n\n      if (value < 0x7f800000) // was value but too large\n      return sign | 0x7c00; // make it +/-Inf\n      return sign\n          | 0x7c00\n          | // remains +/-Inf or NaN\n          (bits & 0x007fffff) >>> 13; // keep NaN (and Inf) bits\n    }\n    if (value >= 0x38800000) { // remains normalized value\n      return sign | value - 0x38000000 >>> 13; // exp - 127 + 15\n    }\n    if (value < 0x33000000) { // too small for subnormal\n      return sign; // becomes +/-0\n    }\n    value = (bits & 0x7fffffff) >>> 23; // tmp exp for subnormal calc\n\n    return sign\n        | ((bits & 0x7fffff | 0x800000) // add subnormal bit\n                + (0x800000 >>> value - 102) // round depending on cut off\n            >>> 126 - value); // div by 2^(1-(exp-127+15)) and >> 13 | exp=0\n  }\n\n  public static final float toFloat(int bits) {\n    int mant = bits & 0x03ff; // 10 bits mantissa\n    int exp = bits & 0x7c00; // 5 bits exponent\n    if (exp == 0x7c00) { // NaN/Inf\n      exp = 0x3fc00; // -> NaN/Inf\n    } else if (exp != 0) { // normalized value\n      exp += 0x1c000; // exp - 15 + 127\n    } else if (mant != 0) { // && exp==0 -> subnormal\n      exp = 0x1c400; // make it normal\n      do {\n        mant <<= 1; // mantissa * 2\n        exp -= 0x400; // decrease exp by 1\n      } while ((mant & 0x400) == 0); // while not normal\n      mant &= 0x3ff; // discard subnormal bit\n    } // else +/-0 -> +/-0\n    return Float.intBitsToFloat( // combine all parts\n        (bits & 0x8000) << 16 // sign  << ( 31 - 15 )\n            | (exp | mant) << 13); // value << ( 23 - 10 )\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/MajorType.java",
    "content": "package org.dhallj.cbor;\n\npublic enum MajorType {\n  UNSIGNED_INTEGER(0),\n  NEGATIVE_INTEGER(1),\n  BYTE_STRING(2),\n  TEXT_STRING(3),\n  ARRAY(4),\n  MAP(5),\n  SEMANTIC_TAG(6),\n  PRIMITIVE(7);\n\n  final int value;\n\n  private MajorType(int value) {\n    this.value = value;\n  }\n\n  public static MajorType fromByte(byte b) {\n    switch ((b & 0xff) >> 5) {\n      case 0:\n        return UNSIGNED_INTEGER;\n      case 1:\n        return NEGATIVE_INTEGER;\n      case 2:\n        return BYTE_STRING;\n      case 3:\n        return TEXT_STRING;\n      case 4:\n        return ARRAY;\n      case 5:\n        return MAP;\n      case 6:\n        return SEMANTIC_TAG;\n      case 7:\n        return PRIMITIVE;\n      default:\n        throw new IllegalArgumentException(\"Invalid CBOR major type \" + Byte.toString(b));\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/NullVisitor.java",
    "content": "package org.dhallj.cbor;\n\nimport java.math.BigInteger;\n\n/** To read a CBOR primitive and ensure it is null. */\nfinal class NullVisitor<R> implements Visitor<R> {\n  static final Visitor<String> instanceForString = new NullVisitor<String>();\n  static final Visitor<byte[]> instanceForByteArray = new NullVisitor<byte[]>();\n\n  @Override\n  public R onUnsignedInteger(BigInteger value) {\n    return notExpected(\"Unsigned integer\");\n  }\n\n  @Override\n  public R onNegativeInteger(BigInteger value) {\n    return notExpected(\"Negative integer\");\n  }\n\n  @Override\n  public R onByteString(byte[] value) {\n    return notExpected(\"Byte string\");\n  }\n\n  @Override\n  public R onTextString(String value) {\n    return notExpected(\"Text string\");\n  }\n\n  @Override\n  public R onVariableArray(BigInteger length, String name) {\n    return notExpected(\"Variable array\");\n  }\n\n  @Override\n  public R onArray(BigInteger length, BigInteger tagI) {\n    return notExpected(\"Array\");\n  }\n\n  @Override\n  public R onMap(BigInteger size) {\n    return notExpected(\"Map\");\n  }\n\n  @Override\n  public R onFalse() {\n    return notExpected(\"False\");\n  }\n\n  @Override\n  public R onTrue() {\n    return notExpected(\"True\");\n  }\n\n  @Override\n  public R onNull() {\n    return null;\n  }\n\n  @Override\n  public R onHalfFloat(float value) {\n    return notExpected(\"Half float\");\n  }\n\n  @Override\n  public R onSingleFloat(float value) {\n    return notExpected(\"Single float\");\n  }\n\n  @Override\n  public R onDoubleFloat(double value) {\n    return notExpected(\"Double float\");\n  }\n\n  @Override\n  public R onTag() {\n    return null;\n  }\n\n  private R notExpected(String msg) {\n    throw new CborException(msg + \" not expected - expected null\");\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/Reader.java",
    "content": "package org.dhallj.cbor;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * An implementation of enough of the CBOR spec to cope with decoding the CBOR values we need for\n * Dhall.\n */\npublic abstract class Reader {\n  private static final BigInteger TWO = new BigInteger(\"2\");\n\n  /** Only allow symbols that correspond to entire encoded Dhall expressions. */\n  public final <R> R nextSymbol(Visitor<R> visitor) {\n    skip55799();\n    byte b = this.read();\n    switch (MajorType.fromByte(b)) {\n      case UNSIGNED_INTEGER:\n        return visitor.onUnsignedInteger(readUnsignedInteger(b));\n      case NEGATIVE_INTEGER:\n        return visitor.onNegativeInteger(readNegativeInteger(b));\n      case BYTE_STRING:\n        return visitor.onByteString(readByteString(b));\n      case TEXT_STRING:\n        return visitor.onTextString(readTextString(b));\n      case ARRAY:\n        return readArrayStart(b, visitor);\n      case MAP:\n        return visitor.onMap(readMapStart(b));\n      case SEMANTIC_TAG:\n        throw new CborException(\"We should have skipped semantic tags\");\n      case PRIMITIVE:\n        return readPrimitive(b, visitor);\n      default:\n        throw new CborException(\"Invalid CBOR major type \" + Byte.toString(b));\n    }\n  }\n\n  protected abstract byte read();\n\n  protected abstract byte peek();\n\n  protected abstract byte[] read(int count);\n\n  public final BigInteger readUnsignedInteger() {\n    skip55799();\n    return readUnsignedInteger(read());\n  }\n\n  public final BigInteger readPositiveBigNum() {\n    skip55799();\n    BigInteger result = readBigNum();\n    if (result.compareTo(BigInteger.ZERO) < 0) {\n      throw new CborException(result.toString() + \" is not a positive big num\");\n    } else {\n      return result;\n    }\n  }\n\n  public final BigInteger readBigNum() {\n    skip55799();\n    byte next = read();\n    switch (MajorType.fromByte(next)) {\n      case UNSIGNED_INTEGER:\n        return readUnsignedInteger(next);\n      case NEGATIVE_INTEGER:\n        return readNegativeInteger(next);\n      case SEMANTIC_TAG:\n        AdditionalInfo info = AdditionalInfo.fromByte(next);\n        BigInteger t = readBigInteger(info, next);\n        long tag = t.longValue();\n        BigInteger length = readUnsignedInteger();\n        long len = length.longValue(); // Don't handle Bignums larger than this\n        BigInteger result = readBigInteger(len);\n        if (tag == 2) {\n          return result;\n        } else if (tag == 3) {\n          return BigInteger.valueOf(-1).subtract(result);\n        } else {\n          throw new CborException(Long.toString(tag) + \" is not a valid tag for a bignum\");\n        }\n      default:\n        throw new CborException(\n            \"Not a valid major type for an Unsigned Integer: \"\n                + MajorType.fromByte(next).toString());\n    }\n  }\n\n  public final BigDecimal readBigDecimal() {\n    skip55799();\n    byte next = read();\n    switch (MajorType.fromByte(next)) {\n      case SEMANTIC_TAG:\n        AdditionalInfo info = AdditionalInfo.fromByte(next);\n        BigInteger t = readBigInteger(info, next);\n        long tag = t.longValue();\n        if (tag == 4) {\n          BigInteger length = readArrayStart();\n          if (length.equals(TWO)) {\n            BigInteger rawScale = readBigNum();\n            int scale = -rawScale.intValue();\n            BigInteger unscaledValue = readBigNum();\n\n            return new BigDecimal(unscaledValue, scale);\n          } else {\n            throw new CborException(\"Invalid decimal fraction\");\n          }\n        } else {\n          throw new CborException(\n              Long.toString(tag) + \" is not a valid tag for a decimal fraction\");\n        }\n      default:\n        throw new CborException(\"Next symbol is not a decimal fraction\");\n    }\n  }\n\n  public final String readNullableTextString() {\n    skip55799();\n    byte next = read();\n    switch (MajorType.fromByte(next)) {\n      case TEXT_STRING:\n        return readTextString(next);\n      case PRIMITIVE:\n        return readPrimitive(next, NullVisitor.instanceForString);\n      default:\n        throw new CborException(\"Next symbol is neither a text string or null\");\n    }\n  }\n\n  public final byte[] readNullableByteString() {\n    skip55799();\n    byte next = read();\n    switch (MajorType.fromByte(next)) {\n      case BYTE_STRING:\n        return readByteString(next);\n      case PRIMITIVE:\n        return readPrimitive(next, NullVisitor.instanceForByteArray);\n      default:\n        throw new CborException(\"Next symbol is neither a byte string or null\");\n    }\n  }\n\n  /**\n   * This is unfortunate and horrible.\n   *\n   * <p>A hack to support decoding record projections, which are the only expressions which have a\n   * CBOR representation where we don't know simply from the length of the array and the first\n   * element what type of expression we're decoding - could be projection or projection by type\n   */\n  public final String tryReadTextString() {\n    skip55799();\n    byte next = peek();\n    switch (MajorType.fromByte(next)) {\n      case TEXT_STRING:\n        return readTextString(read());\n      default:\n        return null;\n    }\n  }\n\n  public final BigInteger readArrayStart() {\n    skip55799();\n    byte next = read();\n    switch (MajorType.fromByte(next)) {\n      case ARRAY:\n        AdditionalInfo info = AdditionalInfo.fromByte(next);\n        BigInteger length = readBigInteger(info, next);\n        if (length.compareTo(BigInteger.ZERO) < 0) {\n          throw new CborException(\"Indefinite array not needed for Dhall\");\n        } else {\n          return length;\n        }\n      default:\n        throw new CborException(\"Next symbol is not an array\");\n    }\n  }\n\n  public final <R> Map<String, R> readMap(Visitor<R> visitor) {\n    skip55799();\n    byte b = this.read();\n    switch (MajorType.fromByte(b)) {\n      case MAP:\n        int length = readMapStart(b).intValue();\n        Map<String, R> entries = new HashMap<>(length);\n        for (int i = 0; i < length; i++) {\n          String key = readNullableTextString();\n          R value = nextSymbol(visitor);\n          entries.put(key, value);\n        }\n        return entries;\n      default:\n        throw new CborException(\n            \"Cannot read map - major type is \" + MajorType.fromByte(b).toString());\n    }\n  }\n\n  private final BigInteger readUnsignedInteger(byte b) {\n    AdditionalInfo info = AdditionalInfo.fromByte(b);\n    return readBigInteger(info, b);\n  }\n\n  private final BigInteger readNegativeInteger(byte b) {\n    AdditionalInfo info = AdditionalInfo.fromByte(b);\n    return BigInteger.valueOf(-1).subtract(readBigInteger(info, b));\n  }\n\n  private final byte[] readByteString(byte b) {\n    AdditionalInfo info = AdditionalInfo.fromByte(b);\n    BigInteger length = readBigInteger(info, b);\n    if (length.compareTo(BigInteger.ZERO) < 0) {\n      throw new CborException(\"Indefinite byte string not needed for Dhall\");\n    } else {\n      // We don't handle the case where the length is > Integer.MaxValue\n      return this.read(length.intValue());\n    }\n  }\n\n  private final String readTextString(byte b) {\n    AdditionalInfo info = AdditionalInfo.fromByte(b);\n    BigInteger length = readBigInteger(info, b);\n    if (length.compareTo(BigInteger.ZERO) < 0) {\n      // Indefinite length - do we need this for Dhall?\n      throw new CborException(\"Indefinite text string not needed for Dhall\");\n    } else {\n      // We don't handle the case where the length is > Integer.MaxValue\n      return new String(this.read(length.intValue()), Charset.forName(\"UTF-8\"));\n    }\n  }\n\n  private final <R> R readArrayStart(byte b, Visitor<R> visitor) {\n    AdditionalInfo info = AdditionalInfo.fromByte(b);\n    BigInteger length = readBigInteger(info, b);\n    if (length.compareTo(BigInteger.ZERO) < 0) {\n      throw new CborException(\"Indefinite array not needed for Dhall\");\n    } else {\n      skip55799();\n      byte next = read();\n      switch (MajorType.fromByte(next)) {\n        case UNSIGNED_INTEGER:\n          return visitor.onArray(length, readUnsignedInteger(next));\n        case TEXT_STRING:\n          return visitor.onVariableArray(length, readTextString(next));\n        default:\n          throw new CborException(\n              \"Invalid start to CBOR-encoded Dhall expression \" + MajorType.fromByte(b).toString());\n      }\n    }\n  }\n\n  private final BigInteger readMapStart(byte b) {\n    AdditionalInfo info = AdditionalInfo.fromByte(b);\n    BigInteger length = readBigInteger(info, b);\n    if (length.compareTo(BigInteger.ZERO) < 0) {\n      throw new CborException(\"Indefinite array not needed for Dhall\");\n    } else {\n      return length;\n    }\n  }\n\n  private static final String unassignedMessage(int v) {\n    StringBuilder builder = new StringBuilder(\"Primitive \");\n    builder.append(v);\n    builder.append(\" is unassigned\");\n    return builder.toString();\n  }\n\n  private static final String notValidMessage(int v) {\n    StringBuilder builder = new StringBuilder(\"Primitive \");\n    builder.append(v);\n    builder.append(\" is not valid\");\n    return builder.toString();\n  }\n\n  private final <R> R readPrimitive(byte b, Visitor<R> visitor) {\n    int value = b & 31;\n    if (0 <= value && value <= 19) {\n      throw new CborException(unassignedMessage(value));\n    } else if (value == 20) {\n      return visitor.onFalse();\n    } else if (value == 21) {\n      return visitor.onTrue();\n    } else if (value == 22) {\n      return visitor.onNull();\n    } else if (value == 23) {\n      throw new CborException(unassignedMessage(value));\n    } else if (value == 24) {\n      throw new CborException(\"Simple value not needed for Dhall\");\n    } else if (value == 25) {\n      // https://github.com/c-rack/cbor-java/blob/master/src/main/java/co/nstant/in/cbor/decoder/HalfPrecisionFloatDecoder.java\n      int bits = 0;\n      for (int i = 0; i < 2; i++) {\n        int next = this.read() & 0xff;\n        bits <<= 8;\n        bits |= next;\n      }\n\n      return visitor.onHalfFloat(HalfFloat.toFloat(bits));\n    } else if (value == 26) {\n      int result = 0;\n      for (int i = 0; i < 4; i++) {\n        int next = this.read() & 0xff;\n        result <<= 8;\n        result |= next;\n      }\n      return visitor.onSingleFloat(Float.intBitsToFloat(result));\n    } else if (value == 27) {\n      long result = 0;\n      for (int i = 0; i < 8; i++) {\n        int next = this.read() & 0xff;\n        result <<= 8;\n        result |= next;\n      }\n      return visitor.onDoubleFloat(Double.longBitsToDouble(result));\n    } else if (28 <= value && value <= 30) {\n      throw new CborException(unassignedMessage(value));\n    } else if (value == 31) {\n      throw new CborException(\"Break stop code not needed for Dhall\");\n    } else {\n      throw new CborException(notValidMessage(value));\n    }\n  }\n\n  private final void skip55799() {\n    byte next = peek();\n    switch (MajorType.fromByte(next)) {\n      case SEMANTIC_TAG:\n        AdditionalInfo info = AdditionalInfo.fromByte(next);\n        switch (info) {\n          case DIRECT:\n            return; // Don't advance pointer if it's a Bignum\n          default:\n            BigInteger tag = readBigInteger(info, read()); // Now advance pointer\n            int t = tag.intValue();\n            if (t != 55799) {\n              throw new CborException(\"Unrecognized CBOR semantic tag \" + Integer.toString(t));\n            } else {\n              skip55799(); // Please tell me no encoders do this\n            }\n        }\n      default:\n    }\n  }\n\n  private final BigInteger readBigInteger(AdditionalInfo info, byte first) {\n    switch (info) {\n      case DIRECT:\n        return BigInteger.valueOf(first & 31);\n      case ONE_BYTE:\n        return readBigInteger(1);\n      case TWO_BYTES:\n        return readBigInteger(2);\n      case FOUR_BYTES:\n        return readBigInteger(4);\n      case EIGHT_BYTES:\n        return readBigInteger(8);\n      case RESERVED:\n        throw new CborException(\"Additional info RESERVED should not require reading a uintXX\");\n      case INDEFINITE:\n        return BigInteger.valueOf(-1);\n      default:\n        throw new IllegalArgumentException(\"Invalid AdditionalInfo\");\n    }\n  }\n\n  private final BigInteger readBigInteger(long numBytes) {\n    BigInteger result = BigInteger.ZERO;\n    for (long i = 0; i < numBytes; i++) {\n      int next = this.read() & 0xff;\n      result = result.shiftLeft(8).or(BigInteger.valueOf(next));\n    }\n    return result;\n  }\n\n  public static final class ByteArrayReader extends Reader {\n    private final byte[] bytes;\n    private int cursor = 0;\n\n    public ByteArrayReader(byte[] bytes) {\n      this.bytes = bytes;\n    }\n\n    @Override\n    protected byte read() {\n      return this.bytes[this.cursor++];\n    }\n\n    @Override\n    protected byte peek() {\n      return this.bytes[this.cursor];\n    }\n\n    @Override\n    protected byte[] read(int count) {\n      byte[] bs = new byte[count];\n\n      System.arraycopy(bytes, this.cursor, bs, 0, count);\n      this.cursor += count;\n\n      return bs;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/Visitor.java",
    "content": "package org.dhallj.cbor;\n\nimport java.math.BigInteger;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Represents a function from a CBOR expression to a value.\n *\n * @param R The result type\n */\npublic interface Visitor<R> {\n\n  public R onUnsignedInteger(BigInteger value);\n\n  public R onNegativeInteger(BigInteger value);\n\n  public R onByteString(byte[] value);\n\n  public R onTextString(String value);\n\n  public R onVariableArray(BigInteger length, String name);\n\n  public R onArray(BigInteger length, BigInteger tagI);\n\n  public R onMap(BigInteger size);\n\n  public R onFalse();\n\n  public R onTrue();\n\n  public R onNull();\n\n  public R onHalfFloat(float value);\n\n  public R onSingleFloat(float value);\n\n  public R onDoubleFloat(double value);\n\n  public R onTag();\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/cbor/Writer.java",
    "content": "package org.dhallj.cbor;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.io.OutputStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.Iterator;\n\npublic abstract class Writer {\n  private static final int FALSE = 244;\n  private static final int TRUE = 245;\n  private static final int NULL = 246;\n  private static final BigInteger LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);\n  private static final BigInteger EIGHT_BYTES_MAX_VALUE = new BigInteger(\"18446744073709551616\");\n  private static final Charset UTF_8 = Charset.forName(\"UTF-8\");\n\n  private static final class WrappedIOException extends RuntimeException {\n    final IOException underlying;\n\n    WrappedIOException(IOException underlying) {\n      this.underlying = underlying;\n    }\n  }\n\n  public static class OutputStreamWriter extends Writer {\n    protected final OutputStream stream;\n\n    public OutputStreamWriter(OutputStream stream) {\n      this.stream = stream;\n    }\n\n    protected final void write(byte b) {\n      try {\n        this.stream.write(b);\n      } catch (IOException e) {\n        throw new WrappedIOException(e);\n      }\n    }\n\n    protected final void write(byte... bs) {\n      try {\n        this.stream.write(bs);\n      } catch (IOException e) {\n        throw new WrappedIOException(e);\n      }\n    }\n  }\n\n  public static final class ByteArrayWriter extends OutputStreamWriter {\n    public ByteArrayWriter() {\n      super(new ByteArrayOutputStream());\n    }\n\n    public final byte[] getBytes() {\n      return ((ByteArrayOutputStream) this.stream).toByteArray();\n    }\n  }\n\n  public static final class SHA256Writer extends Writer {\n    private final MessageDigest messageDigest;\n\n    public SHA256Writer() {\n      MessageDigest tmp = null;\n      try {\n        tmp = MessageDigest.getInstance(\"SHA-256\");\n      } catch (NoSuchAlgorithmException e) {\n        // TODO: Something reasonable here.\n      }\n\n      this.messageDigest = tmp;\n    }\n\n    public final byte[] getHashBytes() {\n      return this.messageDigest.digest();\n    }\n\n    protected final void write(byte b) {\n      this.messageDigest.update(b);\n    }\n\n    protected final void write(byte... bs) {\n      this.messageDigest.update(bs);\n    }\n  }\n\n  protected abstract void write(byte b);\n\n  protected abstract void write(byte... bs);\n\n  public final void writeNull() {\n    this.write((byte) NULL);\n  }\n\n  public final void writeBoolean(boolean value) {\n    this.write((byte) (value ? TRUE : FALSE));\n  }\n\n  public final void writeLong(long value) {\n    if (value >= 0) {\n      this.writeTypeAndLength(MajorType.UNSIGNED_INTEGER.value, value);\n    } else {\n      this.writeTypeAndLength(MajorType.NEGATIVE_INTEGER.value, -(value + 1));\n    }\n  }\n\n  public final void writeBigInteger(BigInteger value) {\n    if (value.compareTo(BigInteger.ZERO) >= 0) {\n      this.writeTypeAndLength(MajorType.UNSIGNED_INTEGER.value, value);\n    } else {\n      this.writeTypeAndLength(MajorType.NEGATIVE_INTEGER.value, value.add(BigInteger.ONE).negate());\n    }\n  }\n\n  public final void writeBigDecimal(BigDecimal value) {\n    this.writeTypeAndLength(MajorType.SEMANTIC_TAG.value, 4);\n    this.writeTypeAndLength(MajorType.ARRAY.value, 2);\n    this.writeLong(-((long) value.scale()));\n    this.writeBigInteger(value.unscaledValue());\n  }\n\n  public final void writeString(String value) {\n    byte[] bytes = value.getBytes(UTF_8);\n    this.writeTypeAndLength(MajorType.TEXT_STRING.value, bytes.length);\n    this.write(bytes);\n  }\n\n  public final void writeByteString(byte[] bytes) {\n    this.writeTypeAndLength(MajorType.BYTE_STRING.value, bytes.length);\n    this.write(bytes);\n  }\n\n  public final void writeDouble(double value) {\n    int base = MajorType.PRIMITIVE.value << 5;\n\n    if (Double.isNaN(value)) {\n      this.write((byte) (base | AdditionalInfo.TWO_BYTES.value), (byte) 126, (byte) 0);\n    } else {\n      float asFloat = (float) value;\n      if (value == (double) asFloat) {\n        int asHalfFloatBits = HalfFloat.fromFloat(asFloat);\n\n        if (HalfFloat.toFloat(asHalfFloatBits) == asFloat) {\n          this.write(\n              (byte) (base | AdditionalInfo.TWO_BYTES.value),\n              (byte) ((asHalfFloatBits >> 8) & 0xff),\n              (byte) ((asHalfFloatBits >> 0) & 0xff));\n        } else {\n\n          int bits = Float.floatToIntBits(asFloat);\n          this.write(\n              (byte) (base | AdditionalInfo.FOUR_BYTES.value),\n              (byte) ((bits >> 24) & 0xff),\n              (byte) ((bits >> 16) & 0xff),\n              (byte) ((bits >> 8) & 0xff),\n              (byte) ((bits >> 0) & 0xff));\n        }\n      } else {\n\n        long bits = Double.doubleToLongBits(value);\n        this.write(\n            (byte) (base | AdditionalInfo.EIGHT_BYTES.value),\n            (byte) ((bits >> 56) & 0xff),\n            (byte) ((bits >> 48) & 0xff),\n            (byte) ((bits >> 40) & 0xff),\n            (byte) ((bits >> 32) & 0xff),\n            (byte) ((bits >> 24) & 0xff),\n            (byte) ((bits >> 16) & 0xff),\n            (byte) ((bits >> 8) & 0xff),\n            (byte) ((bits >> 0) & 0xff));\n      }\n    }\n  }\n\n  public final void writeArrayStart(int length) {\n    this.writeTypeAndLength(MajorType.ARRAY.value, length);\n  }\n\n  public final void writeMapStart(int length) {\n    this.writeTypeAndLength(MajorType.MAP.value, length);\n  }\n\n  private final void writeTypeAndLength(int majorType, long length) {\n    int base = majorType << 5;\n\n    if (length <= 23L) {\n      this.write((byte) (base | length));\n    } else if (length < (1L << 8)) {\n      this.write((byte) (base | AdditionalInfo.ONE_BYTE.value), (byte) length);\n    } else if (length < (1L << 16)) {\n      this.write(\n          (byte) (base | AdditionalInfo.TWO_BYTES.value),\n          (byte) (length >> 8),\n          (byte) (length & 0xff));\n    } else if (length < (1L << 32)) {\n      this.write(\n          (byte) (base | AdditionalInfo.FOUR_BYTES.value),\n          (byte) ((length >> 24) & 0xff),\n          (byte) ((length >> 16) & 0xff),\n          (byte) ((length >> 8) & 0xff),\n          (byte) (length & 0xff));\n    } else {\n      this.write(\n          (byte) (base | AdditionalInfo.EIGHT_BYTES.value),\n          (byte) ((length >> 56) & 0xff),\n          (byte) ((length >> 48) & 0xff),\n          (byte) ((length >> 40) & 0xff),\n          (byte) ((length >> 32) & 0xff),\n          (byte) ((length >> 24) & 0xff),\n          (byte) ((length >> 16) & 0xff),\n          (byte) ((length >> 8) & 0xff),\n          (byte) (length & 0xff));\n    }\n  }\n\n  private final void writeTypeAndLength(int majorType, BigInteger length) {\n    if (length.compareTo(LONG_MAX_VALUE) <= 0) {\n      this.writeTypeAndLength(majorType, length.longValue());\n    } else if (length.compareTo(EIGHT_BYTES_MAX_VALUE) < 0) {\n      int base = majorType << 5;\n      BigInteger mask = BigInteger.valueOf(0xff);\n      this.write(\n          (byte) (base | AdditionalInfo.EIGHT_BYTES.value),\n          length.shiftRight(56).and(mask).byteValue(),\n          length.shiftRight(48).and(mask).byteValue(),\n          length.shiftRight(40).and(mask).byteValue(),\n          length.shiftRight(32).and(mask).byteValue(),\n          length.shiftRight(24).and(mask).byteValue(),\n          length.shiftRight(16).and(mask).byteValue(),\n          length.shiftRight(8).and(mask).byteValue(),\n          length.and(mask).byteValue());\n    } else {\n      if (majorType == MajorType.NEGATIVE_INTEGER.value) {\n        this.writeTypeAndLength(MajorType.SEMANTIC_TAG.value, 3);\n      } else {\n        this.writeTypeAndLength(MajorType.SEMANTIC_TAG.value, 2);\n      }\n      byte[] bs = length.toByteArray();\n      writeTypeAndLength(MajorType.BYTE_STRING.value, bs.length);\n      write(bs);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/ArrayIterable.java",
    "content": "package org.dhallj.core;\n\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\n\nfinal class ArrayIterable<A> implements Iterable<A> {\n  private final A[] values;\n\n  public ArrayIterable(A[] values) {\n    this.values = values;\n  }\n\n  public final Iterator<A> iterator() {\n    return new ArrayIterator<A>(this.values);\n  }\n\n  private static final class ArrayIterator<A> implements Iterator<A> {\n    private final A[] values;\n    private int i = 0;\n\n    ArrayIterator(A[] values) {\n      this.values = values;\n    }\n\n    public final boolean hasNext() {\n      return this.i < this.values.length;\n    }\n\n    public final A next() {\n      try {\n        return this.values[this.i++];\n      } catch (ArrayIndexOutOfBoundsException e) {\n        throw new NoSuchElementException();\n      }\n    }\n\n    public final void remove() {\n      throw new UnsupportedOperationException(\"remove\");\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/Constructors.java",
    "content": "package org.dhallj.core;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Deque;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * Constructors for the Dhall expression abstract syntax tree.\n *\n * <p>Note that nothing in this file is public, and that custom code shouldn't be added here, since\n * this is generated from the visitor definition.\n */\nfinal class Constructors {\n  static final class NaturalLiteral extends Expr {\n    final BigInteger value;\n\n    NaturalLiteral(BigInteger value) {\n      super(Tags.NATURAL);\n      this.value = value;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onNatural(this.value);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onNatural(this, this.value));\n    }\n  }\n\n  static final class IntegerLiteral extends Expr {\n    final BigInteger value;\n\n    IntegerLiteral(BigInteger value) {\n      super(Tags.INTEGER);\n      this.value = value;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onInteger(this.value);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onInteger(this, this.value));\n    }\n  }\n\n  static final class DoubleLiteral extends Expr {\n    final double value;\n\n    DoubleLiteral(double value) {\n      super(Tags.DOUBLE);\n      this.value = value;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onDouble(this.value);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onDouble(this, this.value));\n    }\n  }\n\n  static final class DateLiteral extends Expr {\n    final int year;\n    final int month;\n    final int day;\n\n    DateLiteral(int year, int month, int day) {\n      super(Tags.DATE);\n      this.year = year;\n      this.month = month;\n      this.day = day;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onDate(this.year, this.month, this.day);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onDate(this, this.year, this.month, this.day));\n    }\n  }\n\n  static final class TimeLiteral extends Expr {\n    final int hour;\n    final int minute;\n    final int second;\n    final BigDecimal fractional;\n\n    TimeLiteral(int hour, int minute, int second, BigDecimal fractional) {\n      super(Tags.TIME);\n      this.hour = hour;\n      this.minute = minute;\n      this.second = second;\n      this.fractional = fractional;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onTime(this.hour, this.minute, this.second, this.fractional);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(\n          state.visitor.onTime(this, this.hour, this.minute, this.second, this.fractional));\n    }\n  }\n\n  static final class TimeZoneLiteral extends Expr {\n    final int minutes;\n\n    TimeZoneLiteral(int minutes) {\n      super(Tags.TIME_ZONE);\n      this.minutes = minutes;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onTimeZone(this.minutes);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onTimeZone(this, this.minutes));\n    }\n  }\n\n  static final class TextLiteral extends Expr {\n    final String[] parts;\n    final Expr[] interpolated;\n\n    TextLiteral(String[] parts, Expr[] interpolated) {\n      super(Tags.TEXT);\n      this.parts = parts;\n      this.interpolated = interpolated;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onText(this.parts, new ArrayIterable<Expr>(interpolated));\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareText(this.parts.length);\n        state.visitor.prepareTextPart(this.parts[0]);\n\n        if (this.interpolated.length == 0) {\n          state.valueStack.push(state.visitor.onText(this.parts, new ArrayList<A>()));\n        } else {\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.interpolated[state.current.state - 1], 0));\n        }\n      } else if (state.current.state == this.interpolated.length) {\n        state.visitor.prepareTextPart(this.parts[this.parts.length - 1]);\n        List<A> results = new ArrayList<A>();\n        for (int i = 0; i < this.interpolated.length; i += 1) {\n          results.add(state.valueStack.poll());\n        }\n        Collections.reverse(results);\n        state.valueStack.push(state.visitor.onText(this.parts, results));\n      } else {\n        state.current.state += 1;\n        state.visitor.prepareTextPart(this.parts[state.current.state - 1]);\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.interpolated[state.current.state - 1], 0));\n      }\n    }\n  }\n\n  static final class Application extends Expr {\n    final Expr base;\n    final Expr arg;\n\n    Application(Expr base, Expr arg) {\n      super(Tags.APPLICATION);\n      this.base = base;\n      this.arg = arg;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onApplication(base, arg);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        LinkedList<Expr> application = new LinkedList<>();\n        application.push(this.arg);\n\n        Expr base = Application.gatherApplicationArgs(this.base, application);\n\n        state.current.state = 1;\n        state.current.size = application.size();\n        boolean processBase = state.visitor.prepareApplication(base, application.size());\n        state.current.skippedRecursion = !processBase;\n\n        state.stack.push(state.current);\n\n        if (processBase) {\n          state.stack.push(new ExprState(base, 0));\n        }\n        state.applicationStack.push(application);\n      } else {\n        LinkedList<Expr> application = state.applicationStack.poll();\n\n        if (application.isEmpty()) {\n          List<A> args = new ArrayList<>(state.current.size);\n          for (int i = 0; i < state.current.size; i++) {\n            args.add(state.valueStack.poll());\n          }\n          Collections.reverse(args);\n\n          A base = null;\n          if (!state.current.skippedRecursion) {\n            base = state.valueStack.poll();\n          }\n\n          state.valueStack.push(state.visitor.onApplication(base, args));\n        } else {\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(application.poll(), 0));\n          state.applicationStack.push(application);\n        }\n      }\n    }\n\n    private static final Expr gatherApplicationArgs(Expr candidate, Deque<Expr> args) {\n      Expr current = candidate.getNonNote();\n\n      while (current.tag == Tags.APPLICATION) {\n        Constructors.Application currentApplication = (Constructors.Application) current;\n\n        if (args != null) {\n          args.push(currentApplication.arg);\n        }\n        current = currentApplication.base.getNonNote();\n      }\n\n      return current;\n    }\n  }\n\n  static final class OperatorApplication extends Expr {\n    final Operator operator;\n    final Expr lhs;\n    final Expr rhs;\n\n    OperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n      super(Tags.OPERATOR_APPLICATION);\n      this.operator = operator;\n      this.lhs = lhs;\n      this.rhs = rhs;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onOperatorApplication(this.operator, lhs, rhs);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareOperatorApplication(this.operator);\n        state.current.state = 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.lhs, 0));\n      } else if (state.current.state == 1) {\n        state.current.state = 2;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.rhs, 0));\n      } else {\n        A v1 = state.valueStack.poll();\n        A v0 = state.valueStack.poll();\n        state.valueStack.push(state.visitor.onOperatorApplication(this.operator, v0, v1));\n      }\n    }\n  }\n\n  static final class If extends Expr {\n    final Expr predicate;\n    final Expr thenValue;\n    final Expr elseValue;\n\n    If(Expr predicate, Expr thenValue, Expr elseValue) {\n      super(Tags.IF);\n      this.predicate = predicate;\n      this.thenValue = thenValue;\n      this.elseValue = elseValue;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onIf(predicate, thenValue, elseValue);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareIf();\n        state.current.state = 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.predicate, 0));\n      } else if (state.current.state == 1) {\n        state.current.state = 2;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.thenValue, 0));\n      } else if (state.current.state == 2) {\n        state.current.state = 3;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.elseValue, 0));\n      } else {\n        A v2 = state.valueStack.poll();\n        A v1 = state.valueStack.poll();\n        A v0 = state.valueStack.poll();\n        state.valueStack.push(state.visitor.onIf(v0, v1, v2));\n      }\n    }\n  }\n\n  static final class Lambda extends Expr {\n    final String name;\n    final Expr type;\n    final Expr result;\n\n    Lambda(String name, Expr type, Expr result) {\n      super(Tags.LAMBDA);\n      this.name = name;\n      this.type = type;\n      this.result = result;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onLambda(this.name, type, result);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      switch (state.current.state) {\n        case 0:\n          state.visitor.prepareLambda(this.name, this.type);\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.type, 0));\n          break;\n        case 1:\n          state.visitor.bind(this.name, this.type);\n          state.current.state = 2;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.result, 0));\n          break;\n        case 2:\n          A v1 = state.valueStack.poll();\n          A v0 = state.valueStack.poll();\n          state.valueStack.push(state.visitor.onLambda(this.name, v0, v1));\n          break;\n      }\n    }\n  }\n\n  static final class Pi extends Expr {\n    final String name;\n    final Expr type;\n    final Expr result;\n\n    Pi(String name, Expr type, Expr result) {\n      super(Tags.PI);\n      this.name = name;\n      this.type = type;\n      this.result = result;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onPi(this.name, type, result);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      switch (state.current.state) {\n        case 0:\n          state.visitor.preparePi(this.name, this.type);\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.type, 0));\n          break;\n        case 1:\n          state.visitor.bind(this.name, this.type);\n          state.current.state = 2;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.result, 0));\n          break;\n        case 2:\n          A v1 = state.valueStack.poll();\n          A v0 = state.valueStack.poll();\n          state.valueStack.push(state.visitor.onPi(this.name, v0, v1));\n          break;\n      }\n    }\n  }\n\n  static final class Assert extends Expr {\n    final Expr base;\n\n    Assert(Expr base) {\n      super(Tags.ASSERT);\n      this.base = base;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onAssert(base);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareAssert();\n        state.current.state = 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.base, 0));\n      } else {\n        state.valueStack.push(state.visitor.onAssert(state.valueStack.poll()));\n      }\n    }\n  }\n\n  static final class FieldAccess extends Expr {\n    final Expr base;\n    final String fieldName;\n\n    FieldAccess(Expr base, String fieldName) {\n      super(Tags.FIELD_ACCESS);\n      this.base = base;\n      this.fieldName = fieldName;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onFieldAccess(base, this.fieldName);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        if (state.visitor.prepareFieldAccess(this.base, this.fieldName)) {\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.base, 0));\n        } else {\n          state.valueStack.push(state.visitor.onFieldAccess(null, this.fieldName));\n        }\n      } else {\n        state.valueStack.push(state.visitor.onFieldAccess(state.valueStack.poll(), this.fieldName));\n      }\n    }\n  }\n\n  static final class Projection extends Expr {\n    final Expr base;\n    final String[] fieldNames;\n\n    Projection(Expr base, String[] fieldNames) {\n      super(Tags.PROJECTION);\n      this.base = base;\n      this.fieldNames = fieldNames;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onProjection(base, this.fieldNames);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareProjection(this.fieldNames.length);\n        state.current.state = 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.base, 0));\n      } else {\n        state.valueStack.push(state.visitor.onProjection(state.valueStack.poll(), this.fieldNames));\n      }\n    }\n  }\n\n  static final class ProjectionByType extends Expr {\n    final Expr base;\n    final Expr type;\n\n    ProjectionByType(Expr base, Expr type) {\n      super(Tags.PROJECTION_BY_TYPE);\n      this.base = base;\n      this.type = type;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onProjectionByType(base, type);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareProjectionByType();\n        state.current.state = 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.base, 0));\n      } else if (state.current.state == 1) {\n        state.visitor.prepareProjectionByType(this.type);\n        state.current.state = 2;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.type, 0));\n      } else {\n        A v1 = state.valueStack.poll();\n        A v0 = state.valueStack.poll();\n        state.valueStack.push(state.visitor.onProjectionByType(v0, v1));\n      }\n    }\n  }\n\n  static final class BuiltIn extends Expr {\n    final String name;\n\n    BuiltIn(String name) {\n      super(Tags.BUILT_IN);\n      this.name = name;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onBuiltIn(this.name);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onBuiltIn(this, this.name));\n    }\n  }\n\n  static final class Identifier extends Expr {\n    final String name;\n    final long index;\n\n    Identifier(String name, long index) {\n      super(Tags.IDENTIFIER);\n      this.name = name;\n      this.index = index;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onIdentifier(this.name, this.index);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onIdentifier(this, this.name, this.index));\n    }\n  }\n\n  static final class RecordLiteral extends Expr {\n    final Entry<String, Expr>[] fields;\n\n    RecordLiteral(Entry<String, Expr>[] fields) {\n      super(Tags.RECORD);\n      this.fields = fields;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onRecord(new ArrayIterable<Entry<String, Expr>>(fields), fields.length);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareRecord(this.fields.length);\n        if (this.fields.length == 0) {\n          state.valueStack.push(state.visitor.onRecord(new ArrayList<Entry<String, A>>()));\n        } else {\n          state.current =\n              new ExprState(state.current.expr, 1, this.fields, state.visitor.sortFields());\n          state.stack.push(state.current);\n\n          Entry<String, Expr> field = state.current.sortedFields[state.current.state - 1];\n          state.visitor.prepareRecordField(\n              field.getKey(), field.getValue(), state.current.state - 1);\n          state.stack.push(new ExprState(field.getValue(), 0));\n        }\n      } else if (state.current.state == state.current.sortedFields.length) {\n        List<Entry<String, A>> results = new ArrayList<Entry<String, A>>();\n        for (int i = state.current.sortedFields.length - 1; i >= 0; i -= 1) {\n          results.add(\n              new SimpleImmutableEntry<>(\n                  state.current.sortedFields[i].getKey(), state.valueStack.poll()));\n        }\n        Collections.reverse(results);\n        state.valueStack.push(state.visitor.onRecord(results));\n      } else {\n        state.current.state += 1;\n        Entry<String, Expr> field = state.current.sortedFields[state.current.state - 1];\n\n        state.visitor.prepareRecordField(field.getKey(), field.getValue(), state.current.state - 1);\n\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(field.getValue(), 0));\n      }\n    }\n  }\n\n  static final class RecordType extends Expr {\n    final Entry<String, Expr>[] fields;\n\n    RecordType(Entry<String, Expr>[] fields) {\n      super(Tags.RECORD_TYPE);\n      this.fields = fields;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onRecordType(new ArrayIterable<Entry<String, Expr>>(fields), fields.length);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareRecordType(this.fields.length);\n        if (this.fields.length == 0) {\n          state.valueStack.push(state.visitor.onRecordType(new ArrayList<Entry<String, A>>()));\n        } else {\n          state.current =\n              new ExprState(state.current.expr, 1, this.fields, state.visitor.sortFields());\n          state.stack.push(state.current);\n\n          Entry<String, Expr> field = state.current.sortedFields[state.current.state - 1];\n          state.visitor.prepareRecordTypeField(\n              field.getKey(), field.getValue(), state.current.state - 1);\n          state.stack.push(new ExprState(field.getValue(), 0));\n        }\n      } else if (state.current.state == state.current.sortedFields.length) {\n        List<Entry<String, A>> results = new ArrayList<Entry<String, A>>();\n        for (int i = state.current.sortedFields.length - 1; i >= 0; i -= 1) {\n          results.add(\n              new SimpleImmutableEntry<>(\n                  state.current.sortedFields[i].getKey(), state.valueStack.poll()));\n        }\n        Collections.reverse(results);\n        state.valueStack.push(state.visitor.onRecordType(results));\n      } else {\n        state.current.state += 1;\n        Entry<String, Expr> field = state.current.sortedFields[state.current.state - 1];\n\n        state.visitor.prepareRecordTypeField(\n            field.getKey(), field.getValue(), state.current.state - 1);\n\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(field.getValue(), 0));\n      }\n    }\n  }\n\n  static final class UnionType extends Expr {\n    final Entry<String, Expr>[] fields;\n\n    UnionType(Entry<String, Expr>[] fields) {\n      super(Tags.UNION_TYPE);\n      this.fields = fields;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onUnionType(new ArrayIterable<Entry<String, Expr>>(fields), fields.length);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareUnionType(this.fields.length);\n        if (this.fields.length == 0) {\n          state.valueStack.push(state.visitor.onUnionType(new ArrayList<Entry<String, A>>()));\n        } else {\n          state.current =\n              new ExprState(state.current.expr, 1, this.fields, state.visitor.sortFields());\n          state.stack.push(state.current);\n\n          Entry<String, Expr> field = state.current.sortedFields[state.current.state - 1];\n          state.visitor.prepareUnionTypeField(\n              field.getKey(), field.getValue(), state.current.state - 1);\n\n          Expr type = field.getValue();\n          if (type == null) {\n            state.valueStack.push(null);\n          } else {\n            state.stack.push(new ExprState(type, 0));\n          }\n        }\n      } else if (state.current.state == this.fields.length) {\n        List<Entry<String, A>> results = new ArrayList<Entry<String, A>>();\n        for (int i = state.current.sortedFields.length - 1; i >= 0; i -= 1) {\n          results.add(\n              new SimpleImmutableEntry<>(\n                  state.current.sortedFields[i].getKey(), state.valueStack.poll()));\n        }\n        Collections.reverse(results);\n        state.valueStack.push(state.visitor.onUnionType(results));\n      } else {\n        state.current.state += 1;\n\n        Entry<String, Expr> field = state.current.sortedFields[state.current.state - 1];\n        Expr type = field.getValue();\n\n        state.visitor.prepareUnionTypeField(field.getKey(), type, state.current.state - 1);\n\n        state.stack.push(state.current);\n        if (type == null) {\n          state.valueStack.push(null);\n        } else {\n          state.stack.push(new ExprState(type, 0));\n        }\n      }\n    }\n  }\n\n  static final class NonEmptyListLiteral extends Expr {\n    final Expr[] values;\n\n    NonEmptyListLiteral(Expr[] values) {\n      super(Tags.NON_EMPTY_LIST);\n      this.values = values;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onNonEmptyList(new ArrayIterable<Expr>(values), this.values.length);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        boolean done = false;\n        if (state.visitor.flattenToMapLists()) {\n          Expr asRecord = NonEmptyListLiteral.flattenToMapList(this.values);\n\n          if (asRecord != null) {\n            state.stack.push(new ExprState(asRecord, 0));\n            done = true;\n          }\n        }\n\n        if (!done) {\n          state.visitor.prepareNonEmptyList(this.values.length);\n          state.visitor.prepareNonEmptyListElement(0);\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.values[state.current.state - 1], 0));\n        }\n      } else if (state.current.state == this.values.length) {\n        List<A> results = new ArrayList<A>();\n        for (int i = 0; i < this.values.length; i += 1) {\n          results.add(state.valueStack.poll());\n        }\n        Collections.reverse(results);\n        state.valueStack.push(state.visitor.onNonEmptyList(results));\n      } else {\n        state.visitor.prepareNonEmptyListElement(state.current.state);\n        state.current.state += 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.values[state.current.state - 1], 0));\n      }\n    }\n\n    private static final Expr flattenToMapList(Expr[] values) {\n      LinkedHashMap<String, Expr> fieldMap = new LinkedHashMap<>(values.length);\n\n      for (Expr value : values) {\n        List<Entry<String, Expr>> asRecord = Expr.Util.asRecordLiteral(value);\n\n        if (asRecord == null) {\n          return null;\n        }\n\n        Entry<Expr, Expr> entry = Expr.Util.flattenToMapRecord(asRecord);\n\n        if (entry == null) {\n          return null;\n        }\n\n        String asText = Expr.Util.asSimpleTextLiteral(entry.getKey());\n\n        if (asText == null) {\n          return null;\n        }\n\n        fieldMap.put(asText, entry.getValue());\n      }\n\n      Set<Entry<String, Expr>> fields = fieldMap.entrySet();\n\n      return Expr.makeRecordLiteral(fields.toArray(new Entry[fields.size()]));\n    }\n  }\n\n  static final class EmptyListLiteral extends Expr {\n    final Expr type;\n\n    EmptyListLiteral(Expr type) {\n      super(Tags.EMPTY_LIST);\n      this.type = type;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onEmptyList(type);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        if (state.visitor.flattenToMapLists() && EmptyListLiteral.isToMapListType(this.type)) {\n          state.stack.push(new ExprState(Expr.Constants.EMPTY_RECORD_LITERAL, 0));\n        } else {\n          if (state.visitor.prepareEmptyList(this.type)) {\n            state.current.state = 1;\n            state.stack.push(state.current);\n            state.stack.push(new ExprState(this.type, 0));\n          } else {\n            state.valueStack.push(null);\n          }\n        }\n      } else {\n        state.valueStack.push(state.visitor.onEmptyList(state.valueStack.poll()));\n      }\n    }\n\n    private static final boolean isToMapListType(Expr type) {\n      Expr elementType = Expr.Util.getListArg(type);\n\n      if (elementType == null) {\n        return false;\n      } else {\n        List<Entry<String, Expr>> asRecordType = Expr.Util.asRecordType(elementType);\n\n        if (asRecordType == null) {\n          return false;\n        }\n\n        Entry<Expr, Expr> entry = Expr.Util.flattenToMapRecord(asRecordType);\n\n        if (entry == null) {\n          return false;\n        }\n\n        String asBuiltIn = Expr.Util.asBuiltIn(entry.getKey());\n\n        return asBuiltIn != null && asBuiltIn.equals(\"Text\");\n      }\n    }\n  }\n\n  static final class Let extends Expr {\n    final String name;\n    final Expr type;\n    final Expr value;\n    final Expr body;\n\n    Let(String name, Expr type, Expr value, Expr body) {\n      super(Tags.LET);\n      this.name = name;\n      this.type = type;\n      this.value = value;\n      this.body = body;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onLet(name, type, value, body);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      List<LetBinding<Expr>> letBindings;\n\n      if (state.current.state == 0) {\n        letBindings = new ArrayList<LetBinding<Expr>>();\n        letBindings.add(new LetBinding(this.name, this.type, this.value));\n\n        Let.gatherLetBindings(this.body, letBindings);\n\n        state.current.state = 1;\n        state.current.size = letBindings.size();\n\n        List<String> letBindingNames = new ArrayList<>(state.current.size);\n\n        for (LetBinding<Expr> letBinding : letBindings) {\n          letBindingNames.add(letBinding.getName());\n        }\n\n        state.letBindingNamesStack.push(letBindingNames);\n\n        state.visitor.prepareLet(letBindings.size());\n      } else {\n        letBindings = state.letBindingsStack.poll();\n      }\n\n      if (letBindings.isEmpty()) {\n        if (state.current.state == 1) {\n          state.current.state = 3;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(Let.gatherLetBindings(this.body, null), 0));\n          state.letBindingsStack.push(letBindings);\n        } else {\n          List<String> letBindingNames = state.letBindingNamesStack.poll();\n          LinkedList<LetBinding<A>> valueBindings = new LinkedList<LetBinding<A>>();\n\n          A body = state.valueStack.poll();\n\n          for (int i = 0; i < state.current.size; i++) {\n            A v1 = state.valueStack.poll();\n            A v0 = state.valueStack.poll();\n\n            valueBindings.push(\n                new LetBinding(letBindingNames.get(state.current.size - 1 - i), v0, v1));\n          }\n\n          state.valueStack.push(state.visitor.onLet(valueBindings, body));\n        }\n      } else {\n        LetBinding<Expr> letBinding = letBindings.get(0);\n\n        switch (state.current.state) {\n          case 1:\n            state.current.state = 2;\n            state.visitor.prepareLetBinding(letBinding.getName(), letBinding.getType());\n            if (letBinding.hasType()) {\n              state.stack.push(state.current);\n              state.stack.push(new ExprState(letBinding.getType(), 0));\n              state.letBindingsStack.push(letBindings);\n              break;\n            } else {\n              state.valueStack.push(null);\n            }\n          case 2:\n            state.current.state = 1;\n            state.visitor.bind(letBinding.getName(), letBinding.getType());\n            state.stack.push(state.current);\n            state.stack.push(new ExprState(letBinding.getValue(), 0));\n            letBindings.remove(0);\n            state.letBindingsStack.push(letBindings);\n            break;\n        }\n      }\n    }\n\n    private static final Expr gatherLetBindings(Expr candidate, List<LetBinding<Expr>> args) {\n      Expr current = candidate.getNonNote();\n\n      while (current.tag == Tags.LET) {\n        Constructors.Let currentLet = (Constructors.Let) current;\n\n        if (args != null) {\n          args.add(new LetBinding(currentLet.name, currentLet.type, currentLet.value));\n        }\n        current = currentLet.body.getNonNote();\n      }\n\n      return current;\n    }\n  }\n\n  static final class Annotated extends Expr {\n    final Expr base;\n    final Expr type;\n\n    Annotated(Expr base, Expr type) {\n      super(Tags.ANNOTATED);\n      this.base = base;\n      this.type = type;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onAnnotated(base, type);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      if (state.current.state == 0) {\n        state.visitor.prepareAnnotated(this.type);\n        state.current.state = 1;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.base, 0));\n      } else if (state.current.state == 1) {\n        state.current.state = 2;\n        state.stack.push(state.current);\n        state.stack.push(new ExprState(this.type, 0));\n      } else {\n        A v1 = state.valueStack.poll();\n        A v0 = state.valueStack.poll();\n        state.valueStack.push(state.visitor.onAnnotated(v0, v1));\n      }\n    }\n  }\n\n  static final class Merge extends Expr {\n    final Expr handlers;\n    final Expr union;\n    final Expr type;\n\n    Merge(Expr handlers, Expr union, Expr type) {\n      super(Tags.MERGE);\n      this.handlers = handlers;\n      this.union = union;\n      this.type = type;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onMerge(handlers, union, type);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      switch (state.current.state) {\n        case 0:\n          state.visitor.prepareMerge(this.type);\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.handlers, 0));\n          break;\n        case 1:\n          state.current.state = 2;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.union, 0));\n          break;\n        case 2:\n          state.current.state = 3;\n\n          if (this.type != null) {\n            state.stack.push(state.current);\n            state.stack.push(new ExprState(this.type, 0));\n            break;\n          } else {\n            state.valueStack.push(null);\n          }\n        case 3:\n          A v2 = state.valueStack.poll();\n          A v1 = state.valueStack.poll();\n          A v0 = state.valueStack.poll();\n          state.valueStack.push(state.visitor.onMerge(v0, v1, v2));\n\n          break;\n      }\n    }\n  }\n\n  static final class ToMap extends Expr {\n    final Expr base;\n    final Expr type;\n\n    ToMap(Expr base, Expr type) {\n      super(Tags.TO_MAP);\n      this.base = base;\n      this.type = type;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onToMap(base, type);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      switch (state.current.state) {\n        case 0:\n          state.visitor.prepareToMap(this.type);\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.base, 0));\n          break;\n        case 1:\n          state.current.state = 2;\n\n          if (this.type != null) {\n            state.stack.push(state.current);\n            state.stack.push(new ExprState(this.type, 0));\n            break;\n          } else {\n            state.valueStack.push(null);\n          }\n        case 2:\n          A v1 = state.valueStack.poll();\n          A v0 = state.valueStack.poll();\n          state.valueStack.push(state.visitor.onToMap(v0, v1));\n          break;\n      }\n    }\n  }\n\n  static final class With extends Expr {\n    final Expr base;\n    final String[] path;\n    final Expr value;\n\n    With(Expr base, String[] path, Expr value) {\n      super(Tags.WITH);\n      this.base = base;\n      this.path = path;\n      this.value = value;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onWith(this.base, this.path, this.value);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      switch (state.current.state) {\n        case 0:\n          state.visitor.prepareWith(this.path);\n          state.current.state = 1;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.base, 0));\n          break;\n        case 1:\n          state.visitor.prepareWithValue(this.path);\n          state.current.state = 2;\n          state.stack.push(state.current);\n          state.stack.push(new ExprState(this.value, 0));\n          break;\n        case 2:\n          A v1 = state.valueStack.poll();\n          A v0 = state.valueStack.poll();\n          state.valueStack.push(state.visitor.onWith(v0, this.path, v1));\n          break;\n      }\n    }\n  }\n\n  static final class MissingImport extends Expr {\n    final Expr.ImportMode mode;\n    final byte[] hash;\n\n    MissingImport(Expr.ImportMode mode, byte[] hash) {\n      super(Tags.MISSING_IMPORT);\n      this.mode = mode;\n      this.hash = hash;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onMissingImport(this.mode, this.hash);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onMissingImport(this.mode, this.hash));\n    }\n  }\n\n  static final class EnvImport extends Expr {\n    final String name;\n    final Expr.ImportMode mode;\n    final byte[] hash;\n\n    EnvImport(String name, Expr.ImportMode mode, byte[] hash) {\n      super(Tags.ENV_IMPORT);\n      this.name = name;\n      this.mode = mode;\n      this.hash = hash;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onEnvImport(this.name, this.mode, this.hash);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onEnvImport(this.name, this.mode, this.hash));\n    }\n  }\n\n  static final class LocalImport extends Expr {\n    final Path path;\n    final Expr.ImportMode mode;\n    final byte[] hash;\n\n    LocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      super(Tags.LOCAL_IMPORT);\n      this.path = path;\n      this.mode = mode;\n      this.hash = hash;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onLocalImport(this.path, this.mode, this.hash);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onLocalImport(this.path, this.mode, this.hash));\n    }\n  }\n\n  static final class ClasspathImport extends Expr {\n    final Path path;\n    final Expr.ImportMode mode;\n    final byte[] hash;\n\n    ClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      super(Tags.CLASSPATH_IMPORT);\n      this.path = path;\n      this.mode = mode;\n      this.hash = hash;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onClasspathImport(this.path, this.mode, this.hash);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      state.valueStack.push(state.visitor.onClasspathImport(this.path, this.mode, this.hash));\n    }\n  }\n\n  static final class RemoteImport extends Expr {\n    final URI url;\n    final Expr using;\n    final Expr.ImportMode mode;\n    final byte[] hash;\n\n    RemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n      super(Tags.REMOTE_IMPORT);\n      this.url = url;\n      this.using = using;\n      this.mode = mode;\n      this.hash = hash;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onRemoteImport(this.url, this.using, this.mode, this.hash);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      switch (state.current.state) {\n        case 0:\n          state.visitor.prepareRemoteImport(this.url, this.using, this.mode, this.hash);\n          state.current.state = 1;\n\n          if (this.using != null) {\n            state.stack.push(state.current);\n            state.stack.push(new ExprState(this.using, 0));\n            break;\n          } else {\n            state.valueStack.push(null);\n          }\n        case 1:\n          state.valueStack.push(\n              state.visitor.onRemoteImport(\n                  this.url, state.valueStack.poll(), this.mode, this.hash));\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/DhallException.java",
    "content": "package org.dhallj.core;\n\n/** Base class of exceptions that may be thrown or returned by DhallJ. */\npublic class DhallException extends RuntimeException {\n  public DhallException(String message) {\n    super(message);\n  }\n\n  public DhallException(String message, Throwable cause) {\n    super(message, cause);\n  }\n\n  /** Represents a parsing failure, generally wrapping an underlying exception. */\n  public static final class ParsingFailure extends DhallException {\n    @Override\n    public Throwable fillInStackTrace() {\n      // This is a failure type; stack traces aren't useful.\n      return this;\n    }\n\n    public ParsingFailure(String message, Throwable cause) {\n      super(message, cause);\n    }\n\n    public ParsingFailure(String message) {\n      super(message);\n    }\n  }\n\n  public static final class ResolutionFailure extends DhallException {\n    private boolean isAbsentImport;\n\n    @Override\n    public Throwable fillInStackTrace() {\n      // This is a failure type; stack traces aren't useful.\n      return this;\n    }\n\n    public ResolutionFailure(String message, Throwable cause, boolean isAbsentImport) {\n      super(message, cause);\n      this.isAbsentImport = isAbsentImport;\n    }\n\n    public ResolutionFailure(String message, boolean isAbsentImport) {\n      super(message);\n      this.isAbsentImport = isAbsentImport;\n    }\n\n    public ResolutionFailure(String message, Throwable cause) {\n      this(message, cause, false);\n    }\n\n    public ResolutionFailure(String message) {\n      this(message, false);\n    }\n\n    public boolean isAbsentImport() {\n      return this.isAbsentImport;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/Expr.java",
    "content": "package org.dhallj.core;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Deque;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicReference;\nimport org.dhallj.cbor.Writer;\nimport org.dhallj.core.binary.Encode;\nimport org.dhallj.core.normalization.AlphaNormalize;\nimport org.dhallj.core.normalization.BetaNormalize;\nimport org.dhallj.core.normalization.Shift;\nimport org.dhallj.core.normalization.Substitute;\nimport org.dhallj.core.typechecking.TypeCheck;\n\n/**\n * Represents a Dhall expression.\n *\n * <p>Note that there are two tools for manipulating expressions: internal visitors, which are a\n * fold over the structure, and external visitors, which correspond to pattern matching.\n */\npublic abstract class Expr {\n  final int tag;\n  private final AtomicReference<byte[]> cachedHashBytes = new AtomicReference<byte[]>();\n\n  Expr(int tag) {\n    this.tag = tag;\n  }\n\n  /** Run the given external visitor on this expression. */\n  public abstract <A> A accept(ExternalVisitor<A> visitor);\n\n  abstract <A> void advance(VisitState<A> state);\n\n  /** Run the given internal visitor on this expression. */\n  public final <A> A accept(Visitor<A> visitor) {\n    VisitState<A> state = new VisitState<A>(visitor, this);\n    while (state.current != null) {\n      state.current.expr.advance(state);\n      state.current = state.stack.poll();\n    }\n    return state.valueStack.poll();\n  }\n\n  /**\n   * Beta-normalize this expression.\n   *\n   * <p>This operation \"evaluates\" the expression.\n   */\n  public final Expr normalize() {\n    return this.accept(BetaNormalize.instance);\n  }\n\n  /**\n   * Alpha-normalize this expression.\n   *\n   * <p>This operation replaces all variable names with De-Bruijn-indexed underscores.\n   */\n  public final Expr alphaNormalize() {\n    return this.accept(new AlphaNormalize());\n  }\n\n  /** Increment a variable name in this expression. */\n  public final Expr increment(String name) {\n    return this.accept(new Shift(true, name));\n  }\n\n  /** Increment a variable name in this expression. */\n  public final Expr decrement(String name) {\n    return this.accept(new Shift(false, name));\n  }\n\n  /** Substitute the given expression for the given variable name in this expression. */\n  public final Expr substitute(String name, Expr replacement) {\n    return this.accept(new Substitute(name, replacement));\n  }\n\n  /**\n   * Encode this expression as a CBOR byte array.\n   *\n   * <p>Note that this method does not normalize the expression.\n   */\n  public final byte[] getEncodedBytes() {\n    Writer.ByteArrayWriter writer = new Writer.ByteArrayWriter();\n    this.accept(new Encode(writer));\n    return writer.getBytes();\n  }\n\n  /**\n   * Encode this expression as a CBOR byte array and return the SHA-256 hash of the result.\n   *\n   * <p>Note that this method does not normalize the expression.\n   */\n  public final byte[] getHashBytes() {\n    byte[] result = this.cachedHashBytes.get();\n\n    if (result == null) {\n      Writer.SHA256Writer writer = new Writer.SHA256Writer();\n      this.accept(new Encode(writer));\n      result = writer.getHashBytes();\n\n      if (!this.cachedHashBytes.compareAndSet(null, result)) {\n        return this.cachedHashBytes.get();\n      }\n    }\n    return result;\n  }\n\n  /**\n   * Encode this expression as a CBOR byte array and return the SHA-256 hash of the result as a\n   * string.\n   *\n   * <p>Note that this method does not normalize the expression.\n   */\n  public final String hash() {\n    return Util.encodeHashBytes(this.getHashBytes());\n  }\n\n  /** Check whether all imports in this expression have been resolved. */\n  public final boolean isResolved() {\n    return this.accept(IsResolved.instance);\n  }\n\n  /**\n   * Check whether this expression has the same structure as another.\n   *\n   * <p>This method is a stricter than {@code equivalent} in that it doesn't normalize its\n   * arguments.\n   */\n  public final boolean sameStructure(Expr other) {\n    return this.getFirstDiff(other) == null;\n  }\n\n  /**\n   * Check whether this expression is equivalent to another.\n   *\n   * <p>Note that this method normalizes both expressions before comparing.\n   */\n  public final boolean equivalent(Expr other) {\n    return Arrays.equals(\n        this.normalize().alphaNormalize().getEncodedBytes(),\n        other.normalize().alphaNormalize().getEncodedBytes());\n  }\n\n  /**\n   * Check whether this expression is equivalent to another value.\n   *\n   * <p>Note that this method normalizes both expressions before comparing. Also note that in future\n   * releases this method may compare the hashes of the encoded bytes, but currently it is identical\n   * to equivalent (but with an {@code Object} argument because Java).\n   */\n  public final boolean equals(Object obj) {\n    if (obj instanceof Expr) {\n      return this.equivalent((Expr) obj);\n    } else {\n      return false;\n    }\n  }\n\n  /** Hashes the CBOR encoding of this expression. */\n  public final int hashCode() {\n    return Arrays.hashCode(this.normalize().alphaNormalize().getEncodedBytes());\n  }\n\n  public final String toString() {\n    return this.accept(ToStringVisitor.instance).toString();\n  }\n\n  Expr getNonNote() {\n    Expr current = this;\n\n    while (current.tag == Tags.NOTE) {\n      current = ((Parsed) current).base;\n    }\n\n    return current;\n  }\n\n  /**\n   * Convenience methods for working with expressions.\n   *\n   * <p>Note that many of these operations represent \"down-casts\", and return {@code null} in cases\n   * where the expression doesn't have the requested constructor.\n   */\n  public static final class Util {\n    private Util() {}\n\n    /** Type-check the given expression and return the inferred type. */\n    public static final Expr typeCheck(Expr expr) {\n      return expr.accept(new TypeCheck());\n    }\n\n    /** Return the first difference between the structure of two expressions as a pair. */\n    public static final Entry<Expr, Expr> getFirstDiff(Expr first, Expr second) {\n      return first.getFirstDiff(second);\n    }\n\n    /** Write an encoded expression to a stream. */\n    public static final void encodeToStream(Expr expr, OutputStream stream) {\n      Writer.OutputStreamWriter writer = new Writer.OutputStreamWriter(stream);\n      expr.accept(new Encode(writer));\n    }\n\n    /** Encode an array of bytes as a hex string. */\n    public static String encodeHashBytes(byte[] hash) {\n      StringBuilder hexString = new StringBuilder();\n      for (int i = 0; i < hash.length; i++) {\n        String hex = Integer.toHexString(0xff & hash[i]);\n        if (hex.length() == 1) hexString.append('0');\n        hexString.append(hex);\n      }\n      return hexString.toString();\n    }\n\n    public static final byte[] decodeHashBytes(String input) {\n      byte[] bytes = new byte[input.length() / 2];\n      for (int i = 0; i < input.length(); i += 2) {\n\n        int d1 = Character.digit(input.charAt(i), 16);\n        int d2 = Character.digit(input.charAt(i + 1), 16);\n        bytes[i / 2] = (byte) ((d1 << 4) + d2);\n      }\n      return bytes;\n    }\n\n    /** If the expression is an application of {@code List}, return the element type. */\n    public static Expr getListArg(Expr expr) {\n      return getElementType(expr, \"List\");\n    }\n\n    /** If the expression is an application of {@code Optional}, return the element type. */\n    public static Expr getOptionalArg(Expr expr) {\n      return getElementType(expr, \"Optional\");\n    }\n\n    /** If the expression is an application of {@code Some}, return the element type. */\n    public static Expr getSomeArg(Expr expr) {\n      return getElementType(expr, \"Some\");\n    }\n\n    /** If the expression is an application of {@code None}, return the element type. */\n    public static Expr getNoneArg(Expr expr) {\n      return getElementType(expr, \"None\");\n    }\n\n    /** If the expression is a {@code Bool} literal, return its value. */\n    public static final Boolean asBoolLiteral(Expr expr) {\n      String asBuiltIn = Util.asBuiltIn(expr);\n\n      if (asBuiltIn != null) {\n        if (asBuiltIn.equals(\"True\")) {\n          return true;\n        } else if (asBuiltIn.equals(\"False\")) {\n          return false;\n        }\n      }\n      return null;\n    }\n\n    /** If the expression is a {@code Natural} literal, return its value. */\n    public static final BigInteger asNaturalLiteral(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.NATURAL) {\n        return ((Constructors.NaturalLiteral) value).value;\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is an {@code Integer} literal, return its value. */\n    public static final BigInteger asIntegerLiteral(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.INTEGER) {\n        return ((Constructors.IntegerLiteral) value).value;\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a {@code Double} literal, return its value. */\n    public static final Double asDoubleLiteral(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.DOUBLE) {\n        return ((Constructors.DoubleLiteral) value).value;\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a {@code Text} literal with no interpolations, return its value. */\n    public static final String asSimpleTextLiteral(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.TEXT) {\n        Constructors.TextLiteral text = (Constructors.TextLiteral) value;\n\n        if (text.parts.length == 1) {\n          return text.parts[0];\n        } else {\n          return null;\n        }\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a Dhall built-in, return its name. */\n    public static final String asBuiltIn(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.BUILT_IN) {\n        return ((Constructors.BuiltIn) value).name;\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a {@code List} literal, return its contents. */\n    public static final List<Expr> asListLiteral(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.NON_EMPTY_LIST) {\n        return Arrays.asList(((Constructors.NonEmptyListLiteral) value).values);\n      } else if (value.tag == Tags.EMPTY_LIST) {\n        return new ArrayList<Expr>(0);\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a record literal, return its fields. */\n    public static final List<Entry<String, Expr>> asRecordLiteral(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.RECORD) {\n        return Arrays.asList(((Constructors.RecordLiteral) value).fields);\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a record type, return its fields. */\n    public static final List<Entry<String, Expr>> asRecordType(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.RECORD_TYPE) {\n        return Arrays.asList(((Constructors.RecordType) value).fields);\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a union type, return its fields. */\n    public static final List<Entry<String, Expr>> asUnionType(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.UNION_TYPE) {\n        return Arrays.asList(((Constructors.UnionType) value).fields);\n      } else {\n        return null;\n      }\n    }\n\n    /** If the expression is a field access, return the base and field name. */\n    public static final Entry<Expr, String> asFieldAccess(Expr expr) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.FIELD_ACCESS) {\n        Constructors.FieldAccess fieldAccess = (Constructors.FieldAccess) value;\n        return new SimpleImmutableEntry<>(fieldAccess.base, fieldAccess.fieldName);\n      } else {\n        return null;\n      }\n    }\n\n    /**\n     * If the expression is an application of the specified type constructor, return the element\n     * type.\n     */\n    private static Expr getElementType(Expr expr, String typeConstructor) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.APPLICATION) {\n        Constructors.Application application = (Constructors.Application) value;\n\n        Expr applied = application.base.getNonNote();\n\n        if (applied.tag == Tags.BUILT_IN\n            && ((Constructors.BuiltIn) applied).name.equals(typeConstructor)) {\n          return application.arg;\n        }\n      }\n\n      return null;\n    }\n\n    public static final String escapeText(String input, boolean quoted) {\n      StringBuilder builder = new StringBuilder();\n\n      if (quoted) {\n        builder.append(\"\\\\\\\"\");\n      }\n\n      for (int i = 0; i < input.length(); i++) {\n        char c = input.charAt(i);\n        if (c == '\"') {\n          if (quoted) {\n            builder.append(\"\\\\\\\\\\\"\");\n          } else {\n            builder.append(\"\\\\\\\"\");\n          }\n        } else if (c == '$') {\n          if (quoted) {\n            builder.append(\"\\\\\\\\u0024\");\n          } else {\n            builder.append(\"$\");\n          }\n        } else if (c == '\\\\') {\n          if (quoted) {\n            builder.append(\"\\\\\\\\\");\n          } else {\n            builder.append(\"\\\\\");\n          }\n        } else if (c >= '\\u0000' && c <= '\\u001f') {\n          if (quoted) {\n            builder.append('\\\\');\n          }\n          String asHex = Long.toHexString((long) c);\n\n          builder.append(\"\\\\u\");\n\n          if (asHex.length() < 2) {\n            builder.append('0');\n          }\n          if (asHex.length() < 3) {\n            builder.append('0');\n          }\n          if (asHex.length() < 4) {\n            builder.append('0');\n          }\n          builder.append(asHex);\n        } else {\n          builder.append(c);\n        }\n      }\n      if (quoted) {\n        builder.append(\"\\\\\\\"\");\n      }\n\n      return builder.toString();\n    }\n\n    /** Desugar the complete operator ({@code ::}). */\n    public static final Expr desugarComplete(Expr lhs, Expr rhs) {\n\n      return Expr.makeAnnotated(\n          Expr.makeOperatorApplication(Operator.PREFER, Expr.makeFieldAccess(lhs, \"default\"), rhs),\n          Expr.makeFieldAccess(lhs, \"Type\"));\n    }\n\n    /**\n     * If the expression is a lambda, apply it to the given argument.\n     *\n     * <p>Returns null if the expression is not a lambda.\n     */\n    public static final Expr applyAsLambda(Expr expr, Expr arg) {\n      Expr value = expr.getNonNote();\n\n      if (value.tag == Tags.LAMBDA) {\n        Constructors.Lambda lambda = ((Constructors.Lambda) value);\n        return lambda.result.substitute(lambda.name, arg);\n      } else {\n        return null;\n      }\n    }\n\n    static final Entry<Expr, Expr> flattenToMapRecord(List<Entry<String, Expr>> fields) {\n      if (fields == null || fields.size() != 2) {\n        return null;\n      }\n\n      Expr key = null;\n      Expr value = null;\n\n      for (Entry<String, Expr> entry : fields) {\n        if (entry.getKey().equals(Constants.MAP_KEY_FIELD_NAME)) {\n          key = entry.getValue();\n        } else if (entry.getKey().equals(Constants.MAP_VALUE_FIELD_NAME)) {\n          value = entry.getValue();\n        }\n      }\n\n      if (key == null || value == null) {\n        return null;\n      }\n\n      return new SimpleImmutableEntry<>(key, value);\n    }\n  }\n\n  /** Represents the first part of a {@code let}-expression. */\n  public static final class LetBinding<A> {\n    private final String name;\n    private final A type;\n    private final A value;\n\n    public LetBinding(String name, A type, A value) {\n      this.name = name;\n      this.type = type;\n      this.value = value;\n    }\n\n    public String getName() {\n      return this.name;\n    }\n\n    public boolean hasType() {\n      return this.type != null;\n    }\n\n    public A getType() {\n      return this.type;\n    }\n\n    public A getValue() {\n      return this.value;\n    }\n  }\n\n  /** Modifier specifying how an import should be parsed into a Dhall expression. */\n  public static enum ImportMode {\n    CODE,\n    RAW_TEXT,\n    LOCATION;\n\n    public String toString() {\n      if (this == RAW_TEXT) {\n        return \"Text\";\n      } else if (this == LOCATION) {\n        return \"Location\";\n      } else {\n        return \"Code\";\n      }\n    }\n  }\n\n  /** Definitions of Dhall built-ins and other frequently-used expressions. */\n  public static final class Constants {\n    private static final Entry[] emptyFields = {};\n\n    public static final Expr UNDERSCORE = makeIdentifier(\"_\");\n    public static final Expr SORT = new Constructors.BuiltIn(\"Sort\");\n    public static final Expr KIND = new Constructors.BuiltIn(\"Kind\");\n    public static final Expr TYPE = new Constructors.BuiltIn(\"Type\");\n    public static final Expr BOOL = new Constructors.BuiltIn(\"Bool\");\n    public static final Expr TRUE = new Constructors.BuiltIn(\"True\");\n    public static final Expr FALSE = new Constructors.BuiltIn(\"False\");\n    public static final Expr LIST = new Constructors.BuiltIn(\"List\");\n    public static final Expr OPTIONAL = new Constructors.BuiltIn(\"Optional\");\n    public static final Expr DOUBLE = new Constructors.BuiltIn(\"Double\");\n    public static final Expr NATURAL = new Constructors.BuiltIn(\"Natural\");\n    public static final Expr INTEGER = new Constructors.BuiltIn(\"Integer\");\n    public static final Expr TEXT = new Constructors.BuiltIn(\"Text\");\n    public static final Expr NONE = new Constructors.BuiltIn(\"None\");\n    public static final Expr SOME = new Constructors.BuiltIn(\"Some\");\n\n    public static final Expr DATE = new Constructors.BuiltIn(\"Date\");\n    public static final Expr TIME = new Constructors.BuiltIn(\"Time\");\n    public static final Expr TIME_ZONE = new Constructors.BuiltIn(\"TimeZone\");\n\n    public static final Expr NATURAL_FOLD = new Constructors.BuiltIn(\"Natural/fold\");\n    public static final Expr LIST_FOLD = new Constructors.BuiltIn(\"List/fold\");\n    public static final Expr ZERO = makeNaturalLiteral(BigInteger.ZERO);\n    public static final Expr EMPTY_RECORD_LITERAL = makeRecordLiteral(emptyFields);\n    public static final Expr EMPTY_RECORD_TYPE = makeRecordType(emptyFields);\n    public static final Expr EMPTY_UNION_TYPE = makeUnionType(emptyFields);\n    public static final Expr LOCATION_TYPE =\n        makeUnionType(\n            new Entry[] {\n              new SimpleImmutableEntry<>(\"Environment\", TEXT),\n              new SimpleImmutableEntry<>(\"Local\", TEXT),\n              new SimpleImmutableEntry<>(\"Missing\", null),\n              new SimpleImmutableEntry<>(\"Remote\", TEXT)\n            });\n    public static final String MAP_KEY_FIELD_NAME = \"mapKey\";\n    public static final String MAP_VALUE_FIELD_NAME = \"mapValue\";\n\n    private static final Map<String, Expr> builtIns = new HashMap<String, Expr>(34);\n    private static final Set<String> keywords = new HashSet<String>(16);\n\n    static {\n      builtIns.put(\"Bool\", BOOL);\n      builtIns.put(\"Date\", DATE);\n      builtIns.put(\"Double\", DOUBLE);\n      builtIns.put(\"Double/show\", new Constructors.BuiltIn(\"Double/show\"));\n      builtIns.put(\"False\", FALSE);\n      builtIns.put(\"Integer\", INTEGER);\n      builtIns.put(\"Integer/clamp\", new Constructors.BuiltIn(\"Integer/clamp\"));\n      builtIns.put(\"Integer/negate\", new Constructors.BuiltIn(\"Integer/negate\"));\n      builtIns.put(\"Integer/show\", new Constructors.BuiltIn(\"Integer/show\"));\n      builtIns.put(\"Integer/toDouble\", new Constructors.BuiltIn(\"Integer/toDouble\"));\n      builtIns.put(\"Kind\", KIND);\n      builtIns.put(\"List\", LIST);\n      builtIns.put(\"List/build\", new Constructors.BuiltIn(\"List/build\"));\n      builtIns.put(\"List/fold\", new Constructors.BuiltIn(\"List/fold\"));\n      builtIns.put(\"List/head\", new Constructors.BuiltIn(\"List/head\"));\n      builtIns.put(\"List/indexed\", new Constructors.BuiltIn(\"List/indexed\"));\n      builtIns.put(\"List/last\", new Constructors.BuiltIn(\"List/last\"));\n      builtIns.put(\"List/length\", new Constructors.BuiltIn(\"List/length\"));\n      builtIns.put(\"List/reverse\", new Constructors.BuiltIn(\"List/reverse\"));\n      builtIns.put(\"Natural\", NATURAL);\n      builtIns.put(\"Natural/build\", new Constructors.BuiltIn(\"Natural/build\"));\n      builtIns.put(\"Natural/even\", new Constructors.BuiltIn(\"Natural/even\"));\n      builtIns.put(\"Natural/fold\", new Constructors.BuiltIn(\"Natural/fold\"));\n      builtIns.put(\"Natural/isZero\", new Constructors.BuiltIn(\"Natural/isZero\"));\n      builtIns.put(\"Natural/odd\", new Constructors.BuiltIn(\"Natural/odd\"));\n      builtIns.put(\"Natural/show\", new Constructors.BuiltIn(\"Natural/show\"));\n      builtIns.put(\"Natural/subtract\", new Constructors.BuiltIn(\"Natural/subtract\"));\n      builtIns.put(\"Natural/toInteger\", new Constructors.BuiltIn(\"Natural/toInteger\"));\n      builtIns.put(\"None\", NONE);\n      builtIns.put(\"Optional\", OPTIONAL);\n      builtIns.put(\"Some\", SOME);\n      builtIns.put(\"Sort\", SORT);\n      builtIns.put(\"Text\", TEXT);\n      builtIns.put(\"Text/replace\", new Constructors.BuiltIn(\"Text/replace\"));\n      builtIns.put(\"Text/show\", new Constructors.BuiltIn(\"Text/show\"));\n      builtIns.put(\"Time\", TIME);\n      builtIns.put(\"TimeZone\", TIME_ZONE);\n      builtIns.put(\"True\", TRUE);\n      builtIns.put(\"Type\", TYPE);\n\n      keywords.add(\"if\");\n      keywords.add(\"then\");\n      keywords.add(\"else\");\n      keywords.add(\"let\");\n      keywords.add(\"in\");\n      keywords.add(\"using\");\n      keywords.add(\"missing\");\n      keywords.add(\"assert\");\n      keywords.add(\"as\");\n      keywords.add(\"Infinity\");\n      keywords.add(\"NaN\");\n      keywords.add(\"merge\");\n      keywords.add(\"Some\");\n      keywords.add(\"toMap\");\n      keywords.add(\"forall\");\n      keywords.add(\"with\");\n    }\n\n    static Expr getBuiltIn(String name) {\n      return builtIns.get(name);\n    }\n\n    public static boolean isBuiltIn(String name) {\n      return builtIns.containsKey(name);\n    }\n\n    public static boolean isKeyword(String name) {\n      return keywords.contains(name);\n    }\n  }\n\n  /** Represents a Dhall expression that's been parsed and has associated source information. */\n  public static final class Parsed extends Expr {\n    final Expr base;\n    final Source source;\n\n    public Parsed(Expr base, Source source) {\n      super(Tags.NOTE);\n      this.base = base;\n      this.source = source;\n    }\n\n    public final Source getSource() {\n      return this.source;\n    }\n\n    public final <A> A accept(ExternalVisitor<A> visitor) {\n      return visitor.onNote(base, this.source);\n    }\n\n    final <A> void advance(VisitState<A> state) {\n      this.base.advance(state);\n    }\n  }\n\n  public static final Expr makeDoubleLiteral(double value) {\n    return new Constructors.DoubleLiteral(value);\n  }\n\n  public static final Expr makeNaturalLiteral(BigInteger value) {\n    return new Constructors.NaturalLiteral(value);\n  }\n\n  public static final Expr makeIntegerLiteral(BigInteger value) {\n    return new Constructors.IntegerLiteral(value);\n  }\n\n  public static final Expr makeDateLiteral(int year, int month, int day) {\n    return new Constructors.DateLiteral(year, month, day);\n  }\n\n  public static final Expr makeTimeLiteral(\n      int hour, int minute, int second, BigDecimal fractional) {\n    return new Constructors.TimeLiteral(hour, minute, second, fractional);\n  }\n\n  public static final Expr makeTimeZoneLiteral(int seconds) {\n    return new Constructors.TimeZoneLiteral(seconds);\n  }\n\n  public static final Expr makeTextLiteral(String[] parts, Expr[] interpolated) {\n    return new Constructors.TextLiteral(parts, interpolated);\n  }\n\n  public static final Expr makeTextLiteral(String[] parts, Collection<Expr> interpolated) {\n    return new Constructors.TextLiteral(parts, interpolated.toArray(new Expr[interpolated.size()]));\n  }\n\n  private static final Expr[] emptyExprArray = {};\n\n  public static final Expr makeTextLiteral(String value) {\n    String[] parts = {value};\n    return new Constructors.TextLiteral(parts, emptyExprArray);\n  }\n\n  public static final Expr makeApplication(Expr base, Expr arg) {\n    return new Constructors.Application(base, arg);\n  }\n\n  public static final Expr makeApplication(Expr base, Expr[] args) {\n    Expr acc = base;\n    for (int i = 0; i < args.length; i++) {\n      acc = Expr.makeApplication(acc, args[i]);\n    }\n    return acc;\n  }\n\n  public static final Expr makeApplication(Expr base, List<Expr> args) {\n    Expr acc = base;\n    for (int i = 0; i < args.size(); i++) {\n      acc = Expr.makeApplication(acc, args.get(i));\n    }\n    return acc;\n  }\n\n  public static final Expr makeOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    return new Constructors.OperatorApplication(operator, lhs, rhs);\n  }\n\n  public static final Expr makeIf(Expr cond, Expr thenValue, Expr elseValue) {\n    return new Constructors.If(cond, thenValue, elseValue);\n  }\n\n  public static final Expr makeLambda(String param, Expr input, Expr result) {\n    return new Constructors.Lambda(param, input, result);\n  }\n\n  public static final Expr makePi(String param, Expr input, Expr result) {\n    return new Constructors.Pi(param, input, result);\n  }\n\n  public static final Expr makePi(Expr input, Expr result) {\n    return makePi(\"_\", input, result);\n  }\n\n  public static final Expr makeAssert(Expr base) {\n    return new Constructors.Assert(base);\n  }\n\n  public static final Expr makeFieldAccess(Expr base, String fieldName) {\n    return new Constructors.FieldAccess(base, fieldName);\n  }\n\n  public static final Expr makeProjection(Expr base, String[] fieldNames) {\n    return new Constructors.Projection(base, fieldNames);\n  }\n\n  public static final Expr makeProjectionByType(Expr base, Expr tpe) {\n    return new Constructors.ProjectionByType(base, tpe);\n  }\n\n  public static final Expr makeBuiltIn(String name) {\n    if (Constants.getBuiltIn(name) == null) {\n      throw new IllegalArgumentException(name + \" is not a built-in\");\n    }\n    return Constants.getBuiltIn(name);\n  }\n\n  public static final Expr makeIdentifier(String name, long index) {\n    return new Constructors.Identifier(name, index);\n  }\n\n  public static final Expr makeIdentifier(String name) {\n    return makeIdentifier(name, 0);\n  }\n\n  public static final Expr makeRecordLiteral(Entry<String, Expr>[] fields) {\n    return new Constructors.RecordLiteral(fields);\n  }\n\n  public static final Expr makeRecordLiteral(Collection<Entry<String, Expr>> fields) {\n    return new Constructors.RecordLiteral(fields.toArray(new Entry[fields.size()]));\n  }\n\n  public static final Expr makeRecordLiteral(String key, Expr value) {\n    return new Constructors.RecordLiteral(new Entry[] {new SimpleImmutableEntry<>(key, value)});\n  }\n\n  public static final Expr makeRecordType(Entry<String, Expr>[] fields) {\n    return new Constructors.RecordType(fields);\n  }\n\n  public static final Expr makeRecordType(Collection<Entry<String, Expr>> fields) {\n    return new Constructors.RecordType(fields.toArray(new Entry[fields.size()]));\n  }\n\n  public static final Expr makeUnionType(Entry<String, Expr>[] fields) {\n    return new Constructors.UnionType(fields);\n  }\n\n  public static final Expr makeUnionType(Collection<Entry<String, Expr>> fields) {\n    return new Constructors.UnionType(fields.toArray(new Entry[fields.size()]));\n  }\n\n  public static final Expr makeNonEmptyListLiteral(Expr[] values) {\n    return new Constructors.NonEmptyListLiteral(values);\n  }\n\n  public static final Expr makeNonEmptyListLiteral(Collection<Expr> values) {\n    return new Constructors.NonEmptyListLiteral(values.toArray(new Expr[values.size()]));\n  }\n\n  public static final Expr makeEmptyListLiteral(Expr tpe) {\n    return new Constructors.EmptyListLiteral(tpe);\n  }\n\n  public static final Expr makeNote(Expr base, Source source) {\n    return new Parsed(base, source);\n  }\n\n  public static final Expr makeLet(String name, Expr type, Expr value, Expr body) {\n    return new Constructors.Let(name, type, value, body);\n  }\n\n  public static final Expr makeLet(List<LetBinding<Expr>> bindings, Expr body) {\n    Expr result = body;\n\n    for (int i = bindings.size() - 1; i >= 0; i--) {\n      LetBinding<Expr> binding = bindings.get(i);\n      result =\n          new Constructors.Let(binding.getName(), binding.getType(), binding.getValue(), result);\n    }\n\n    return result;\n  }\n\n  public static final Expr makeLet(String name, Expr value, Expr body) {\n    return makeLet(name, null, value, body);\n  }\n\n  public static final Expr makeAnnotated(Expr base, Expr type) {\n    return new Constructors.Annotated(base, type);\n  }\n\n  public static final Expr makeToMap(Expr base, Expr type) {\n    return new Constructors.ToMap(base, type);\n  }\n\n  public static final Expr makeToMap(Expr base) {\n    return makeToMap(base, null);\n  }\n\n  public static final Expr makeWith(Expr base, String[] path, Expr value) {\n    return new Constructors.With(base, path, value);\n  }\n\n  public static final Expr makeMerge(Expr left, Expr right, Expr type) {\n    return new Constructors.Merge(left, right, type);\n  }\n\n  public static final Expr makeMerge(Expr left, Expr right) {\n    return makeMerge(left, right, null);\n  }\n\n  public static final Expr makeLocalImport(Path path, ImportMode mode, byte[] hash) {\n    return new Constructors.LocalImport(path, mode, hash);\n  }\n\n  public static final Expr makeClasspathImport(Path path, ImportMode mode, byte[] hash) {\n    return new Constructors.ClasspathImport(path, mode, hash);\n  }\n\n  public static final Expr makeRemoteImport(URI url, Expr using, ImportMode mode, byte[] hash) {\n    return new Constructors.RemoteImport(url, using, mode, hash);\n  }\n\n  public static final Expr makeEnvImport(String value, ImportMode mode, byte[] hash) {\n    return new Constructors.EnvImport(value, mode, hash);\n  }\n\n  public static final Expr makeMissingImport(ImportMode mode, byte[] hash) {\n    return new Constructors.MissingImport(mode, hash);\n  }\n\n  private final Entry<Expr, Expr> getFirstDiff(Expr other) {\n    Deque<Expr> stackA = new ArrayDeque<Expr>();\n    Deque<Expr> stackB = new ArrayDeque<Expr>();\n\n    Expr currentA = this;\n    Expr currentB = other;\n\n    stackA.add(currentA);\n    stackB.add(currentB);\n\n    while (true) {\n      currentA = stackA.poll();\n      currentB = stackB.poll();\n\n      if (currentA == null || currentB == null) {\n        break;\n      }\n\n      currentA = currentA.getNonNote();\n      currentB = currentB.getNonNote();\n\n      if (currentA.tag != currentB.tag) {\n        break;\n      }\n\n      if (currentA.tag == Tags.NATURAL) {\n        if (((Constructors.NaturalLiteral) currentA)\n            .value.equals(((Constructors.NaturalLiteral) currentB).value)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.INTEGER) {\n        if (((Constructors.IntegerLiteral) currentA)\n            .value.equals(((Constructors.IntegerLiteral) currentB).value)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.DOUBLE) {\n        // We must compare double literals using the binary encoding.\n        if (Arrays.equals(currentA.getEncodedBytes(), currentB.getEncodedBytes())) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.BUILT_IN) {\n        Constructors.BuiltIn builtInA = (Constructors.BuiltIn) currentA;\n        Constructors.BuiltIn builtInB = (Constructors.BuiltIn) currentB;\n        if (builtInA.name.equals(builtInB.name)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.IDENTIFIER) {\n        Constructors.Identifier identifierA = (Constructors.Identifier) currentA;\n        Constructors.Identifier identifierB = (Constructors.Identifier) currentB;\n        if (identifierA.name.equals(identifierB.name) && identifierA.index == identifierB.index) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.LAMBDA) {\n        Constructors.Lambda lambdaA = (Constructors.Lambda) currentA;\n        Constructors.Lambda lambdaB = (Constructors.Lambda) currentB;\n        if (lambdaA.name.equals(lambdaB.name)) {\n          stackA.add(lambdaA.type);\n          stackB.add(lambdaB.type);\n          stackA.add(lambdaA.result);\n          stackB.add(lambdaB.result);\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.PI) {\n        Constructors.Pi piA = (Constructors.Pi) currentA;\n        Constructors.Pi piB = (Constructors.Pi) currentB;\n        if (piA.name.equals(piB.name) && !(piA.type == null ^ piB.type == null)) {\n          if (piA.type != null) {\n            stackA.add(piA.type);\n            stackB.add(piB.type);\n          }\n          stackA.add(piA.result);\n          stackB.add(piB.result);\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.LET) {\n        Constructors.Let letA = (Constructors.Let) currentA;\n        Constructors.Let letB = (Constructors.Let) currentB;\n        if (letA.name.equals(letB.name) && !(letA.type == null ^ letB.type == null)) {\n          if (letA.type != null) {\n            stackA.add(letA.type);\n            stackB.add(letB.type);\n          }\n          stackA.add(letA.value);\n          stackB.add(letB.value);\n          stackA.add(letA.body);\n          stackB.add(letB.body);\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.TEXT) {\n        Constructors.TextLiteral textA = (Constructors.TextLiteral) currentA;\n        Constructors.TextLiteral textB = (Constructors.TextLiteral) currentB;\n        if (Arrays.equals(textA.interpolated, textB.interpolated)) {\n          for (Expr interpolation : textA.interpolated) {\n            stackA.add(interpolation);\n          }\n\n          for (Expr interpolation : textB.interpolated) {\n            stackB.add(interpolation);\n          }\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.NON_EMPTY_LIST) {\n        Constructors.NonEmptyListLiteral nonEmptyListA =\n            (Constructors.NonEmptyListLiteral) currentA;\n        Constructors.NonEmptyListLiteral nonEmptyListB =\n            (Constructors.NonEmptyListLiteral) currentB;\n        for (Expr value : nonEmptyListA.values) {\n          stackA.add(value);\n        }\n\n        for (Expr value : nonEmptyListB.values) {\n          stackB.add(value);\n        }\n        continue;\n      } else if (currentA.tag == Tags.EMPTY_LIST) {\n        Constructors.EmptyListLiteral emptyListA = (Constructors.EmptyListLiteral) currentA;\n        Constructors.EmptyListLiteral emptyListB = (Constructors.EmptyListLiteral) currentB;\n        stackA.add(emptyListA.type);\n        stackB.add(emptyListB.type);\n        continue;\n      } else if (currentA.tag == Tags.RECORD) {\n        Constructors.RecordLiteral recordA = (Constructors.RecordLiteral) currentA;\n        Constructors.RecordLiteral recordB = (Constructors.RecordLiteral) currentB;\n        Entry<String, Expr>[] fieldsA = recordA.fields;\n        Entry<String, Expr>[] fieldsB = recordB.fields;\n\n        if (fieldsA.length == fieldsB.length) {\n          for (int i = 0; i < fieldsA.length; i++) {\n            if (!fieldsA[i].getKey().equals(fieldsB[i].getKey())) {\n              return new SimpleImmutableEntry<>(fieldsA[i].getValue(), fieldsB[i].getValue());\n            }\n\n            stackA.add(fieldsA[i].getValue());\n            stackB.add(fieldsB[i].getValue());\n          }\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.RECORD_TYPE) {\n        Constructors.RecordType recordTypeA = (Constructors.RecordType) currentA;\n        Constructors.RecordType recordTypeB = (Constructors.RecordType) currentB;\n        Entry<String, Expr>[] fieldsA = recordTypeA.fields;\n        Entry<String, Expr>[] fieldsB = recordTypeB.fields;\n\n        if (fieldsA.length == fieldsB.length) {\n          for (int i = 0; i < fieldsA.length; i++) {\n            if (!fieldsA[i].getKey().equals(fieldsB[i].getKey())) {\n              return new SimpleImmutableEntry<>(fieldsA[i].getValue(), fieldsB[i].getValue());\n            }\n\n            stackA.add(fieldsA[i].getValue());\n            stackB.add(fieldsB[i].getValue());\n          }\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.UNION_TYPE) {\n        Constructors.UnionType unionTypeA = (Constructors.UnionType) currentA;\n        Constructors.UnionType unionTypeB = (Constructors.UnionType) currentB;\n        Entry<String, Expr>[] fieldsA = unionTypeA.fields;\n        Entry<String, Expr>[] fieldsB = unionTypeB.fields;\n\n        if (fieldsA.length == fieldsB.length) {\n          for (int i = 0; i < fieldsA.length; i++) {\n            if (!fieldsA[i].getKey().equals(fieldsB[i].getKey())) {\n              return new SimpleImmutableEntry<>(fieldsA[i].getValue(), fieldsB[i].getValue());\n            }\n\n            if (fieldsA[i].getValue() != null && fieldsB[i].getValue() != null) {\n              stackA.add(fieldsA[i].getValue());\n              stackB.add(fieldsB[i].getValue());\n            } else if (fieldsA[i].getValue() == null ^ fieldsB[i].getValue() == null) {\n              return new SimpleImmutableEntry<>(currentA, currentB);\n            }\n          }\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.FIELD_ACCESS) {\n        Constructors.FieldAccess fieldAccessA = (Constructors.FieldAccess) currentA;\n        Constructors.FieldAccess fieldAccessB = (Constructors.FieldAccess) currentB;\n\n        if (fieldAccessA.fieldName.equals(fieldAccessB.fieldName)) {\n          stackA.add(fieldAccessA.base);\n          stackB.add(fieldAccessB.base);\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.PROJECTION) {\n        Constructors.Projection projectionA = (Constructors.Projection) currentA;\n        Constructors.Projection projectionB = (Constructors.Projection) currentB;\n\n        if (Arrays.equals(projectionA.fieldNames, projectionB.fieldNames)) {\n          stackA.add(projectionA.base);\n          stackB.add(projectionB.base);\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.PROJECTION_BY_TYPE) {\n        Constructors.ProjectionByType projectionByTypeA = (Constructors.ProjectionByType) currentA;\n        Constructors.ProjectionByType projectionByTypeB = (Constructors.ProjectionByType) currentB;\n\n        stackA.add(projectionByTypeA.base);\n        stackB.add(projectionByTypeB.base);\n        stackA.add(projectionByTypeA.type);\n        stackB.add(projectionByTypeB.type);\n        continue;\n      } else if (currentA.tag == Tags.APPLICATION) {\n        Constructors.Application applicationA = (Constructors.Application) currentA;\n        Constructors.Application applicationB = (Constructors.Application) currentB;\n\n        stackA.add(applicationA.base);\n        stackB.add(applicationB.base);\n        stackA.add(applicationA.arg);\n        stackB.add(applicationB.arg);\n        continue;\n      } else if (currentA.tag == Tags.OPERATOR_APPLICATION) {\n        Constructors.OperatorApplication operatorApplicationA =\n            (Constructors.OperatorApplication) currentA;\n        Constructors.OperatorApplication operatorApplicationB =\n            (Constructors.OperatorApplication) currentB;\n\n        if (operatorApplicationA.operator.equals(operatorApplicationB.operator)) {\n          stackA.add(operatorApplicationA.lhs);\n          stackB.add(operatorApplicationB.lhs);\n          stackA.add(operatorApplicationA.rhs);\n          stackB.add(operatorApplicationB.rhs);\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.IF) {\n        Constructors.If ifA = (Constructors.If) currentA;\n        Constructors.If ifB = (Constructors.If) currentB;\n\n        stackA.add(ifA.predicate);\n        stackB.add(ifB.predicate);\n        stackA.add(ifA.thenValue);\n        stackB.add(ifB.thenValue);\n        stackA.add(ifA.elseValue);\n        stackB.add(ifB.elseValue);\n        continue;\n      } else if (currentA.tag == Tags.ANNOTATED) {\n        Constructors.Annotated annotatedA = (Constructors.Annotated) currentA;\n        Constructors.Annotated annotatedB = (Constructors.Annotated) currentB;\n\n        stackA.add(annotatedA.base);\n        stackB.add(annotatedB.base);\n        stackA.add(annotatedA.type);\n        stackB.add(annotatedB.type);\n        continue;\n      } else if (currentA.tag == Tags.ASSERT) {\n        Constructors.Assert assertA = (Constructors.Assert) currentA;\n        Constructors.Assert assertB = (Constructors.Assert) currentB;\n\n        stackA.add(assertA.base);\n        stackB.add(assertB.base);\n        continue;\n      } else if (currentA.tag == Tags.MERGE) {\n        Constructors.Merge mergeA = (Constructors.Merge) currentA;\n        Constructors.Merge mergeB = (Constructors.Merge) currentB;\n        if (!(mergeA.type == null ^ mergeB.type == null)) {\n          stackA.add(mergeA.handlers);\n          stackB.add(mergeB.handlers);\n          stackA.add(mergeA.union);\n          stackB.add(mergeB.union);\n          if (mergeA.type != null) {\n            stackA.add(mergeA.type);\n            stackB.add(mergeB.type);\n          }\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.TO_MAP) {\n        Constructors.ToMap toMapA = (Constructors.ToMap) currentA;\n        Constructors.ToMap toMapB = (Constructors.ToMap) currentB;\n        if (!(toMapA.type == null ^ toMapB.type == null)) {\n          stackA.add(toMapA.base);\n          stackB.add(toMapB.base);\n          if (toMapA.type != null) {\n            stackA.add(toMapA.type);\n            stackB.add(toMapB.type);\n          }\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.MISSING_IMPORT) {\n        Constructors.MissingImport missingImportA = (Constructors.MissingImport) currentA;\n        Constructors.MissingImport missingImportB = (Constructors.MissingImport) currentB;\n        if (missingImportA.mode.equals(missingImportB.mode)\n            && Arrays.equals(missingImportA.hash, missingImportB.hash)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.ENV_IMPORT) {\n        Constructors.EnvImport envImportA = (Constructors.EnvImport) currentA;\n        Constructors.EnvImport envImportB = (Constructors.EnvImport) currentB;\n        if (envImportA.name.equals(envImportB.name)\n            && envImportA.mode.equals(envImportB.mode)\n            && Arrays.equals(envImportA.hash, envImportB.hash)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.LOCAL_IMPORT) {\n        Constructors.LocalImport localImportA = (Constructors.LocalImport) currentA;\n        Constructors.LocalImport localImportB = (Constructors.LocalImport) currentB;\n        if (localImportA.path.equals(localImportB.path)\n            && localImportA.mode.equals(localImportB.mode)\n            && Arrays.equals(localImportA.hash, localImportB.hash)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.CLASSPATH_IMPORT) {\n        Constructors.ClasspathImport classpathImportA = (Constructors.ClasspathImport) currentA;\n        Constructors.ClasspathImport classpathImportB = (Constructors.ClasspathImport) currentB;\n        if (classpathImportA.path.equals(classpathImportB.path)\n            && classpathImportA.mode.equals(classpathImportB.mode)\n            && Arrays.equals(classpathImportA.hash, classpathImportB.hash)) {\n          continue;\n        } else {\n          break;\n        }\n      } else if (currentA.tag == Tags.REMOTE_IMPORT) {\n        Constructors.RemoteImport remoteImportA = (Constructors.RemoteImport) currentA;\n        Constructors.RemoteImport remoteImportB = (Constructors.RemoteImport) currentB;\n        if (remoteImportA.url.equals(remoteImportB.url)\n            && remoteImportA.mode.equals(remoteImportB.mode)\n            && Arrays.equals(remoteImportA.hash, remoteImportB.hash)) {\n          continue;\n        } else {\n          break;\n        }\n      }\n    }\n\n    if (currentA == null && currentB == null) {\n      return null;\n    } else {\n      return new SimpleImmutableEntry<>(currentA, currentB);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/ExternalVisitor.java",
    "content": "package org.dhallj.core;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.Map.Entry;\n\n/**\n * Represents a function from a Dhall expression to a value.\n *\n * @param A The result type\n */\npublic interface ExternalVisitor<A> {\n  A onNote(Expr base, Source source);\n\n  A onNatural(BigInteger value);\n\n  A onInteger(BigInteger value);\n\n  A onDouble(double value);\n\n  A onDate(int year, int month, int day);\n\n  A onTime(int hour, int minute, int second, BigDecimal fractional);\n\n  A onTimeZone(int minutes);\n\n  A onBuiltIn(String name);\n\n  A onIdentifier(String name, long index);\n\n  A onLambda(String name, Expr type, Expr result);\n\n  A onPi(String name, Expr type, Expr result);\n\n  A onLet(String name, Expr type, Expr value, Expr body);\n\n  A onText(String[] parts, Iterable<Expr> interpolated);\n\n  A onNonEmptyList(Iterable<Expr> values, int size);\n\n  A onEmptyList(Expr type);\n\n  A onRecord(Iterable<Entry<String, Expr>> fields, int size);\n\n  A onRecordType(Iterable<Entry<String, Expr>> fields, int size);\n\n  A onUnionType(Iterable<Entry<String, Expr>> fields, int size);\n\n  A onFieldAccess(Expr base, String fieldName);\n\n  A onProjection(Expr base, String[] fieldNames);\n\n  A onProjectionByType(Expr base, Expr type);\n\n  A onApplication(Expr base, Expr arg);\n\n  A onOperatorApplication(Operator operator, Expr lhs, Expr rhs);\n\n  A onIf(Expr predicate, Expr thenValue, Expr elseValue);\n\n  A onAnnotated(Expr base, Expr type);\n\n  A onAssert(Expr base);\n\n  A onMerge(Expr handlers, Expr union, Expr type);\n\n  A onToMap(Expr base, Expr type);\n\n  A onWith(Expr base, String[] path, Expr value);\n\n  A onMissingImport(Expr.ImportMode mode, byte[] hash);\n\n  A onEnvImport(String value, Expr.ImportMode mode, byte[] hash);\n\n  A onLocalImport(Path path, Expr.ImportMode mode, byte[] hash);\n\n  A onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash);\n\n  A onRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash);\n\n  /**\n   * Represents a function from a Dhall expression that always returns the same value.\n   *\n   * <p>This is a convenience class designed to help with implementations that have a default value\n   * for most cases.\n   *\n   * <p>Note that by default the implementation sees through note layers.\n   *\n   * @param A The result type\n   */\n  public static class Constant<A> implements ExternalVisitor<A> {\n    private final A returnValue;\n\n    protected A getReturnValue() {\n      return this.returnValue;\n    }\n\n    public Constant(A value) {\n      this.returnValue = value;\n    }\n\n    @Override\n    public A onNote(Expr base, Source source) {\n      return base.accept(this);\n    }\n\n    @Override\n    public A onNatural(BigInteger value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onInteger(BigInteger value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onDouble(double value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onDate(int year, int month, int day) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onTime(int hour, int minute, int second, BigDecimal fractional) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onTimeZone(int minutes) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onBuiltIn(String name) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onIdentifier(String name, long index) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onLambda(String name, Expr input, Expr result) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onPi(String name, Expr input, Expr result) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onLet(String name, Expr type, Expr value, Expr body) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onText(String[] parts, Iterable<Expr> interpolated) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onNonEmptyList(Iterable<Expr> values, int size) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onEmptyList(Expr tpe) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onRecord(Iterable<Entry<String, Expr>> fields, int size) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onRecordType(Iterable<Entry<String, Expr>> fields, int size) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onUnionType(Iterable<Entry<String, Expr>> fields, int size) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onFieldAccess(Expr base, String fieldName) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onProjection(Expr base, String[] fieldNames) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onProjectionByType(Expr base, Expr tpe) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onApplication(Expr base, Expr arg) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onIf(Expr predicate, Expr thenValue, Expr elseValue) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onAnnotated(Expr base, Expr tpe) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onAssert(Expr base) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onMerge(Expr handlers, Expr union, Expr tpe) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onToMap(Expr base, Expr type) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onWith(Expr base, String[] path, Expr value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onMissingImport(Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/IsResolved.java",
    "content": "package org.dhallj.core;\n\nimport java.net.URI;\nimport java.nio.file.Path;\n\nfinal class IsResolved extends Visitor.Property {\n  public static final Visitor<Boolean> instance = new IsResolved();\n\n  @Override\n  public Boolean onOperatorApplication(Operator operator, Boolean lhs, Boolean rhs) {\n    if (operator.equals(Operator.IMPORT_ALT)) {\n      return false;\n    } else {\n      return super.onOperatorApplication(operator, lhs, rhs);\n    }\n  }\n\n  @Override\n  public Boolean onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    return false;\n  }\n\n  @Override\n  public Boolean onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    return false;\n  }\n\n  @Override\n  public Boolean onRemoteImport(URI url, Boolean using, Expr.ImportMode mode, byte[] hash) {\n    return false;\n  }\n\n  @Override\n  public Boolean onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n    return false;\n  }\n\n  @Override\n  public Boolean onMissingImport(Expr.ImportMode mode, byte[] hash) {\n    return false;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/Operator.java",
    "content": "package org.dhallj.core;\n\n/** Represents a Dhall operator. */\npublic enum Operator {\n  OR(\"||\", 3, true),\n  AND(\"&&\", 7, true),\n  EQUALS(\"==\", 12, true),\n  NOT_EQUALS(\"!=\", 13, true),\n  PLUS(\"+\", 4, false),\n  TIMES(\"*\", 11, false),\n  TEXT_APPEND(\"++\", 5, false),\n  LIST_APPEND(\"#\", 6, false),\n  COMBINE(\"\\u2227\", 8, false),\n  PREFER(\"\\u2afd\", 9, false),\n  COMBINE_TYPES(\"\\u2a53\", 10, false),\n  IMPORT_ALT(\"?\", 2, false),\n  EQUIVALENT(\"\\u2261\", 1, false),\n  COMPLETE(\"::\", 0, false);\n\n  private static final Operator[] values = values();\n\n  private final String value;\n  private final int precedence;\n  private final boolean isBoolOperator;\n\n  Operator(String value, int precedence, boolean isBoolOperator) {\n    this.value = value;\n    this.precedence = precedence;\n    this.isBoolOperator = isBoolOperator;\n  }\n\n  public final boolean isBoolOperator() {\n    return this.isBoolOperator;\n  }\n\n  public final int getLabel() {\n    return this.ordinal();\n  }\n\n  public final int getPrecedence() {\n    return this.precedence;\n  }\n\n  public final String toString() {\n    return this.value;\n  }\n\n  public static final Operator fromLabel(int ordinal) {\n    if (ordinal >= 0 && ordinal < values.length) {\n      return values[ordinal];\n    } else {\n      return null;\n    }\n  }\n\n  public static final Operator parse(String input) {\n    if (input.equals(OR.value)) {\n      return OR;\n    } else if (input.equals(AND.value)) {\n      return AND;\n    } else if (input.equals(EQUALS.value)) {\n      return EQUALS;\n    } else if (input.equals(NOT_EQUALS.value)) {\n      return NOT_EQUALS;\n    } else if (input.equals(PLUS.value)) {\n      return PLUS;\n    } else if (input.equals(TIMES.value)) {\n      return TIMES;\n    } else if (input.equals(TEXT_APPEND.value)) {\n      return TEXT_APPEND;\n    } else if (input.equals(LIST_APPEND.value)) {\n      return LIST_APPEND;\n    } else if (input.equals(COMBINE.value) || input.equals(\"/\\\\\")) {\n      return COMBINE;\n    } else if (input.equals(PREFER.value) || input.equals(\"//\")) {\n      return PREFER;\n    } else if (input.equals(COMBINE_TYPES.value) || input.equals(\"//\\\\\\\\\")) {\n      return COMBINE_TYPES;\n    } else if (input.equals(IMPORT_ALT.value)) {\n      return IMPORT_ALT;\n    } else if (input.equals(EQUIVALENT.value) || input.equals(\"===\")) {\n      return EQUIVALENT;\n    } else if (input.equals(COMPLETE.value)) {\n      return COMPLETE;\n    } else {\n      throw new IllegalArgumentException(\"No org.dhallj.core.Operator represented by \" + input);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/Source.java",
    "content": "package org.dhallj.core;\n\n/** Represents a section of a source document corresponding to a parsed expression. */\npublic abstract class Source {\n  final int beginLine;\n  final int beginColumn;\n  final int endLine;\n  final int endColumn;\n\n  public Source(int beginLine, int beginColumn, int endLine, int endColumn) {\n    this.beginLine = beginLine;\n    this.beginColumn = beginColumn;\n    this.endLine = endLine;\n    this.endColumn = endColumn;\n  }\n\n  public abstract void printText(StringBuilder builder);\n\n  public final String getText() {\n    StringBuilder builder = new StringBuilder();\n    this.printText(builder);\n    return builder.toString();\n  }\n\n  public final int getBeginLine() {\n    return this.beginLine;\n  }\n\n  public final int getBeginColumn() {\n    return this.beginColumn;\n  }\n\n  public final int getEndLine() {\n    return this.endLine;\n  }\n\n  public final int getEndColumn() {\n    return this.endColumn;\n  }\n\n  public final String toString() {\n    StringBuilder builder = new StringBuilder(\"[(\");\n    builder.append(this.beginLine);\n    builder.append(\", \");\n    builder.append(this.beginColumn);\n    builder.append(\") (\");\n    builder.append(this.endLine);\n    builder.append(\", \");\n    builder.append(this.endColumn);\n    builder.append(\")]\\n\");\n    this.printText(builder);\n    return builder.toString();\n  }\n\n  private static final class FromString extends Source {\n    private final String text;\n\n    FromString(String text, int beginLine, int beginColumn, int endLine, int endColumn) {\n      super(beginLine, beginColumn, endLine, endColumn);\n      this.text = text;\n    }\n\n    public final void printText(StringBuilder builder) {\n      builder.append(this.text);\n    }\n  }\n\n  public static final Source fromString(\n      String text, int beginLine, int beginColumn, int endLine, int endColumn) {\n    return new FromString(text, beginLine, beginColumn, endLine, endColumn);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/Tags.java",
    "content": "package org.dhallj.core;\n\n// Note that these are internal identifiers only.\nfinal class Tags {\n  static final int NOTE = 0;\n\n  // Non-recursive constructors.\n  static final int NATURAL = 1;\n  static final int INTEGER = 2;\n  static final int DOUBLE = 3;\n  static final int BUILT_IN = 4;\n  static final int IDENTIFIER = 5;\n  static final int DATE = 31;\n  static final int TIME = 32;\n  static final int TIME_ZONE = 33;\n\n  // Binding constructors.\n  static final int LAMBDA = 6;\n  static final int PI = 7;\n  static final int LET = 8;\n\n  // Other.\n  static final int TEXT = 9;\n  static final int NON_EMPTY_LIST = 10;\n  static final int EMPTY_LIST = 11;\n\n  static final int RECORD = 12;\n  static final int RECORD_TYPE = 13;\n  static final int UNION_TYPE = 14;\n\n  static final int FIELD_ACCESS = 15;\n  static final int PROJECTION = 16;\n  static final int PROJECTION_BY_TYPE = 17;\n\n  static final int APPLICATION = 18;\n  static final int OPERATOR_APPLICATION = 19;\n  static final int IF = 20;\n  static final int ANNOTATED = 21;\n  static final int ASSERT = 22;\n\n  // Syntactic sugar.\n  static final int MERGE = 23;\n  static final int TO_MAP = 24;\n\n  // Imports.\n  static final int MISSING_IMPORT = 25;\n  static final int ENV_IMPORT = 26;\n  static final int LOCAL_IMPORT = 27;\n  static final int REMOTE_IMPORT = 28;\n  static final int CLASSPATH_IMPORT = 29;\n\n  static final int WITH = 30;\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/ToStringVisitor.java",
    "content": "package org.dhallj.core;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.charset.Charset;\nimport java.nio.file.Path;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map.Entry;\n\nfinal class ToStringState {\n  static final int NONE = 0;\n  static final int OPERATOR = 1;\n  static final int APPLICATION = Operator.NOT_EQUALS.getPrecedence() + 1;\n  static final int IMPORT = APPLICATION + 1;\n  static final int COMPLETE = IMPORT + 1;\n  static final int SELECTOR = COMPLETE + 1;\n  static final int PRIMITIVE = SELECTOR + 1;\n\n  private final String text;\n  private final int level;\n\n  ToStringState(String text, int level) {\n    this.text = text;\n    this.level = level;\n  }\n\n  ToStringState(String text) {\n    this(text, PRIMITIVE);\n  }\n\n  ToStringState withText(String text) {\n    return new ToStringState(text, this.level);\n  }\n\n  String toString(int contextLevel) {\n    if (this.level < contextLevel) {\n      return \"(\" + this.text + \")\";\n    } else {\n      return this.text;\n    }\n  }\n\n  public String toString() {\n    return this.toString(NONE);\n  }\n\n  static final int getOperatorLevel(Operator operator) {\n    if (operator == Operator.COMPLETE) {\n      return COMPLETE;\n    } else {\n      return operator.getPrecedence();\n    }\n  }\n}\n\nfinal class ToStringVisitor extends Visitor.NoPrepareEvents<ToStringState> {\n  public static Visitor<ToStringState> instance = new ToStringVisitor();\n\n  public void bind(String name, Expr type) {}\n\n  public ToStringState onNote(ToStringState base, Source source) {\n    return base;\n  }\n\n  public ToStringState onNatural(Expr self, BigInteger value) {\n    return new ToStringState(value.toString());\n  }\n\n  public ToStringState onInteger(Expr self, BigInteger value) {\n    String withSign =\n        (value.compareTo(BigInteger.ZERO) >= 0) ? (\"+\" + value.toString()) : value.toString();\n    return new ToStringState(withSign);\n  }\n\n  public ToStringState onDouble(Expr self, double value) {\n    return new ToStringState(Double.toString(value));\n  }\n\n  private static String pad2(int input) {\n    String asString = Integer.toString(input);\n    if (asString.length() == 1) {\n      return \"0\" + asString;\n    } else {\n      return asString;\n    }\n  }\n\n  private static String pad4(int input) {\n    String asString = Integer.toString(input);\n    for (int i = 0; i < asString.length() - 4; i += 1) {\n      asString = \"0\" + asString;\n    }\n    return asString;\n  }\n\n  public ToStringState onDate(Expr self, int year, int month, int day) {\n    return new ToStringState(pad4(year) + \"-\" + pad2(month) + \"-\" + pad2(day));\n  }\n\n  public ToStringState onTime(Expr self, int hour, int minute, int second, BigDecimal fractional) {\n    String result = pad2(hour) + \":\" + pad2(minute) + \":\" + pad2(second);\n\n    if (!fractional.equals(BigDecimal.ZERO)) {\n      result = result + fractional.toString().substring(1);\n    }\n\n    return new ToStringState(result);\n  }\n\n  public ToStringState onTimeZone(Expr self, int minutes) {\n    if (Long.signum(minutes) < 0) {\n      return new ToStringState(\"-\" + pad2(-minutes / 60) + \":\" + pad2(-minutes % 60));\n    } else {\n      return new ToStringState(\"+\" + pad2(minutes / 60) + \":\" + pad2(minutes % 60));\n    }\n  }\n\n  public ToStringState onBuiltIn(Expr self, String name) {\n    return new ToStringState(name);\n  }\n\n  public ToStringState onIdentifier(Expr self, String name, long index) {\n    String maybeEscaped = escapeName(name);\n    return new ToStringState(\n        (index == 0) ? maybeEscaped : (maybeEscaped + \"@\" + Long.toString(index)));\n  }\n\n  public ToStringState onRecord(List<Entry<String, ToStringState>> fields) {\n    if (fields.isEmpty()) {\n      return new ToStringState(\"{=}\");\n    } else {\n      StringBuilder builder = new StringBuilder(\"{\");\n      Iterator<Entry<String, ToStringState>> it = fields.iterator();\n      while (it.hasNext()) {\n        Entry<String, ToStringState> entry = it.next();\n        builder.append(escapeName(entry.getKey()));\n        builder.append(\" = \");\n        builder.append(entry.getValue().toString());\n        if (it.hasNext()) {\n          builder.append(\", \");\n        }\n      }\n      builder.append(\"}\");\n\n      return new ToStringState(builder.toString());\n    }\n  }\n\n  public ToStringState onRecordType(List<Entry<String, ToStringState>> fields) {\n    StringBuilder builder = new StringBuilder(\"{\");\n    Iterator<Entry<String, ToStringState>> it = fields.iterator();\n    while (it.hasNext()) {\n      Entry<String, ToStringState> entry = it.next();\n      builder.append(escapeName(entry.getKey()));\n      builder.append(\" : \");\n      builder.append(entry.getValue().toString());\n      if (it.hasNext()) {\n        builder.append(\", \");\n      }\n    }\n    builder.append(\"}\");\n\n    return new ToStringState(builder.toString());\n  }\n\n  public ToStringState onUnionType(List<Entry<String, ToStringState>> fields) {\n    StringBuilder builder = new StringBuilder(\"<\");\n    Iterator<Entry<String, ToStringState>> it = fields.iterator();\n    while (it.hasNext()) {\n      Entry<String, ToStringState> entry = it.next();\n      builder.append(escapeName(entry.getKey()));\n      ToStringState type = entry.getValue();\n      if (type != null) {\n        builder.append(\" : \");\n        builder.append(type.toString());\n      }\n      if (it.hasNext()) {\n        builder.append(\" | \");\n      }\n    }\n    builder.append(\">\");\n\n    return new ToStringState(builder.toString());\n  }\n\n  public ToStringState onNonEmptyList(List<ToStringState> values) {\n    StringBuilder builder = new StringBuilder(\"[\");\n    Iterator<ToStringState> it = values.iterator();\n    while (it.hasNext()) {\n      builder.append(it.next().toString());\n      if (it.hasNext()) {\n        builder.append(\", \");\n      }\n    }\n    builder.append(\"]\");\n\n    return new ToStringState(builder.toString());\n  }\n\n  public ToStringState onFieldAccess(ToStringState base, String fieldName) {\n    return new ToStringState(\n        base.toString(ToStringState.PRIMITIVE) + \".\" + fieldName, ToStringState.SELECTOR);\n  }\n\n  public ToStringState onProjection(ToStringState base, String[] fieldNames) {\n    StringBuilder builder = new StringBuilder(base.toString(ToStringState.PRIMITIVE));\n    builder.append(\".{\");\n    for (int i = 0; i < fieldNames.length; i += 1) {\n      builder.append(fieldNames[i]);\n      if (i < fieldNames.length - 1) {\n        builder.append(\", \");\n      }\n    }\n    builder.append(\"}\");\n\n    return new ToStringState(builder.toString(), ToStringState.SELECTOR);\n  }\n\n  public ToStringState onProjectionByType(ToStringState base, ToStringState type) {\n    return new ToStringState(\n        base.toString(ToStringState.PRIMITIVE) + \".(\" + type.toString() + \")\",\n        ToStringState.SELECTOR);\n  }\n\n  public ToStringState onOperatorApplication(\n      Operator operator, ToStringState lhs, ToStringState rhs) {\n    int operatorLevel = ToStringState.getOperatorLevel(operator);\n\n    if (operatorLevel == ToStringState.COMPLETE) {\n      return new ToStringState(\n          lhs.toString(ToStringState.SELECTOR)\n              + \" \"\n              + operator.toString()\n              + \" \"\n              + rhs.toString(ToStringState.SELECTOR),\n          operatorLevel);\n\n    } else {\n      return new ToStringState(\n          lhs.toString(operatorLevel)\n              + \" \"\n              + operator.toString()\n              + \" \"\n              + rhs.toString(operatorLevel + 1),\n          operatorLevel);\n    }\n  }\n\n  public ToStringState onMissingImport(Expr.ImportMode mode, byte[] hash) {\n    StringBuilder builder = new StringBuilder(\"missing\");\n\n    if (hash != null) {\n      builder.append(\" \");\n      builder.append(Expr.Util.encodeHashBytes(hash));\n    }\n\n    if (mode != Expr.ImportMode.CODE) {\n      builder.append(\" as \");\n      builder.append(mode);\n    }\n\n    return new ToStringState(builder.toString(), ToStringState.IMPORT);\n  }\n\n  public ToStringState onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n    StringBuilder builder = new StringBuilder(\"env:\");\n    builder.append(value);\n\n    if (hash != null) {\n      builder.append(\" \");\n      builder.append(Expr.Util.encodeHashBytes(hash));\n    }\n\n    if (mode != Expr.ImportMode.CODE) {\n      builder.append(\" as \");\n      builder.append(mode);\n    }\n\n    return new ToStringState(builder.toString(), ToStringState.IMPORT);\n  }\n\n  public ToStringState onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    StringBuilder builder = new StringBuilder(path.toString());\n\n    if (hash != null) {\n      builder.append(\" \");\n      builder.append(Expr.Util.encodeHashBytes(hash));\n    }\n\n    if (mode != Expr.ImportMode.CODE) {\n      builder.append(\" as \");\n      builder.append(mode);\n    }\n\n    return new ToStringState(builder.toString(), ToStringState.IMPORT);\n  }\n\n  @Override\n  public ToStringState onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    StringBuilder builder = new StringBuilder(\"classpath:\");\n\n    builder.append(path.toString());\n\n    if (hash != null) {\n      builder.append(\" \");\n      builder.append(Expr.Util.encodeHashBytes(hash));\n    }\n\n    if (mode != Expr.ImportMode.CODE) {\n      builder.append(\" as \");\n      builder.append(mode);\n    }\n\n    return new ToStringState(builder.toString(), ToStringState.IMPORT);\n  }\n\n  public ToStringState onRemoteImport(\n      URI url, ToStringState using, Expr.ImportMode mode, byte[] hash) {\n    StringBuilder builder = new StringBuilder(url.toString());\n\n    if (using != null) {\n      builder.append(\" using \");\n      builder.append(using.toString(ToStringState.IMPORT));\n    }\n\n    if (hash != null) {\n      builder.append(\" \");\n      builder.append(Expr.Util.encodeHashBytes(hash));\n    }\n\n    if (mode != Expr.ImportMode.CODE) {\n      builder.append(\" as \");\n      builder.append(mode);\n    }\n\n    return new ToStringState(builder.toString(), ToStringState.IMPORT);\n  }\n\n  public ToStringState onMerge(ToStringState handlers, ToStringState union, ToStringState type) {\n    StringBuilder builder = new StringBuilder(\"merge \");\n\n    builder.append(handlers.toString(ToStringState.IMPORT));\n    builder.append(\" \");\n    builder.append(union.toString(ToStringState.IMPORT));\n    if (type != null) {\n      builder.append(\" : \");\n      builder.append(type.toString(ToStringState.APPLICATION));\n      return new ToStringState(builder.toString(), ToStringState.NONE);\n    } else {\n      return new ToStringState(builder.toString(), ToStringState.APPLICATION);\n    }\n  }\n\n  public ToStringState onLambda(String name, ToStringState type, ToStringState result) {\n    return new ToStringState(\n        \"λ(\" + escapeName(name) + \" : \" + type.toString() + \") → \" + result.toString(),\n        ToStringState.NONE);\n  }\n\n  public ToStringState onPi(String name, ToStringState type, ToStringState result) {\n    String resultString = result.toString();\n\n    return new ToStringState(\n        name.equals(\"_\")\n            ? (type.toString(ToStringState.OPERATOR) + \" → \" + resultString)\n            : (\"∀(\" + escapeName(name) + \" : \" + type.toString() + \") → \" + resultString),\n        ToStringState.NONE);\n  }\n\n  public ToStringState onLet(List<Expr.LetBinding<ToStringState>> bindings, ToStringState body) {\n    String result = body.toString();\n\n    for (int i = bindings.size() - 1; i >= 0; i--) {\n      Expr.LetBinding<ToStringState> binding = bindings.get(i);\n\n      String typeString = binding.hasType() ? (\" : \" + binding.getType().toString()) : \"\";\n\n      result =\n          \"let \"\n              + escapeName(binding.getName())\n              + typeString\n              + \" = \"\n              + binding.getValue().toString()\n              + \" in \"\n              + result;\n    }\n\n    return new ToStringState(result, ToStringState.NONE);\n  }\n\n  public ToStringState onText(String[] parts, List<ToStringState> interpolated) {\n\n    StringBuilder builder = new StringBuilder(\"\\\"\");\n    builder.append(Expr.Util.escapeText(parts[0], false));\n    int i = 1;\n    Iterator<ToStringState> it = interpolated.iterator();\n\n    while (it.hasNext()) {\n      builder.append(\"${\");\n      builder.append(it.next().toString());\n      builder.append(\"}\");\n      builder.append(Expr.Util.escapeText(parts[i++], false));\n    }\n    if (i < parts.length) {\n      builder.append(Expr.Util.escapeText(parts[i], false));\n    }\n    builder.append(\"\\\"\");\n    return new ToStringState(builder.toString());\n  }\n\n  public ToStringState onEmptyList(ToStringState type) {\n    return new ToStringState(\n        \"[] : \" + type.toString(ToStringState.APPLICATION), ToStringState.NONE);\n  }\n\n  public ToStringState onApplication(ToStringState base, List<ToStringState> args) {\n    StringBuilder builder = new StringBuilder(base.toString(ToStringState.IMPORT));\n    builder.append(\" \");\n\n    for (int i = 0; i < args.size(); i += 1) {\n      builder.append(args.get(i).toString(ToStringState.IMPORT));\n      if (i < args.size() - 1) {\n        builder.append(\" \");\n      }\n    }\n\n    return new ToStringState(builder.toString(), ToStringState.APPLICATION);\n  }\n\n  public ToStringState onIf(\n      ToStringState predicate, ToStringState thenValue, ToStringState elseValue) {\n    return new ToStringState(\n        \"if \"\n            + predicate.toString()\n            + \" then \"\n            + thenValue.toString()\n            + \" else \"\n            + elseValue.toString(),\n        ToStringState.NONE);\n  }\n\n  public ToStringState onAnnotated(ToStringState base, ToStringState type) {\n    return new ToStringState(\n        base.toString(ToStringState.OPERATOR) + \" : \" + type.toString(), ToStringState.NONE);\n  }\n\n  public ToStringState onAssert(ToStringState base) {\n    return new ToStringState(\"assert : \" + base.toString(), ToStringState.NONE);\n  }\n\n  public ToStringState onToMap(ToStringState base, ToStringState type) {\n    StringBuilder builder = new StringBuilder(\"toMap \");\n\n    builder.append(base.toString(ToStringState.IMPORT));\n    if (type != null) {\n      builder.append(\" : \");\n      builder.append(type.toString(ToStringState.APPLICATION));\n      return new ToStringState(builder.toString(), ToStringState.NONE);\n    } else {\n      return new ToStringState(builder.toString(), ToStringState.APPLICATION);\n    }\n  }\n\n  public ToStringState onWith(ToStringState base, String[] path, ToStringState value) {\n    StringBuilder builder = new StringBuilder();\n\n    builder.append(base.toString(ToStringState.IMPORT));\n    builder.append(\" with \");\n    for (int i = 0; i < path.length - 1; i += 1) {\n      builder.append(path[i]);\n      builder.append(\".\");\n    }\n    builder.append(path[path.length - 1]);\n    builder.append(\" = \");\n    builder.append(value.toString(ToStringState.OPERATOR));\n\n    return new ToStringState(builder.toString(), ToStringState.NONE);\n  }\n\n  private static boolean isAlpha(char c) {\n    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');\n  }\n\n  private static boolean isDigit(char c) {\n    return (c >= '0' && c <= '9');\n  }\n\n  private static boolean isSimpleLabel(String name) {\n    if (name.length() == 0) {\n      return false;\n    }\n\n    char c = name.charAt(0);\n    if (!isAlpha(c) && c != '_') {\n      return false;\n    }\n\n    for (int i = 1; i < name.length(); i++) {\n      c = name.charAt(i);\n      if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '/' && c != '_') {\n        return false;\n      }\n    }\n\n    return true;\n  }\n\n  private static String escapeName(String name) {\n    if (!isSimpleLabel(name) || Expr.Constants.isBuiltIn(name) || Expr.Constants.isKeyword(name)) {\n      return \"`\" + name + \"`\";\n    } else {\n      return name;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/VisitState.java",
    "content": "package org.dhallj.core;\n\nimport java.util.ArrayDeque;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.Deque;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map.Entry;\n\nfinal class ExprState {\n  final Expr expr;\n  int state;\n  int size;\n  Entry<String, Expr>[] sortedFields;\n  boolean skippedRecursion = false;\n\n  ExprState(Expr expr, int state, int size) {\n    this.expr = expr;\n    this.state = state;\n    this.size = size;\n    this.sortedFields = null;\n  }\n\n  ExprState(Expr expr, int state, Entry<String, Expr>[] fields, boolean sortFields) {\n    this.expr = expr;\n    this.state = state;\n    this.size = 0;\n    if (sortFields) {\n      this.sortedFields = new Entry[fields.length];\n      System.arraycopy(fields, 0, sortedFields, 0, fields.length);\n      Arrays.sort(sortedFields, ExprState.entryComparator);\n    } else {\n      this.sortedFields = fields;\n    }\n  }\n\n  ExprState(Expr expr, int state) {\n    this(expr, state, 0);\n  }\n\n  /** Java 8 introduces {@code comparingByKey}, but we can roll our own pretty easily. */\n  private static final Comparator<Entry<String, Expr>> entryComparator =\n      new Comparator<Entry<String, Expr>>() {\n        public int compare(Entry<String, Expr> a, Entry<String, Expr> b) {\n          return a.getKey().compareTo(b.getKey());\n        }\n      };\n}\n\nfinal class VisitState<A> {\n  final Visitor<A> visitor;\n\n  ExprState current;\n  final Deque<ExprState> stack;\n  final Deque<A> valueStack;\n\n  final Deque<LinkedList<Expr>> applicationStack;\n  final Deque<List<Expr.LetBinding<Expr>>> letBindingsStack;\n  final Deque<List<String>> letBindingNamesStack;\n\n  public VisitState(Visitor<A> visitor, Expr expr) {\n    this.visitor = visitor;\n    this.current = new ExprState(expr, 0);\n    this.stack = new ArrayDeque<>();\n    // Note that we have to use a linked list here because we store null values on the stack.\n    this.valueStack = new LinkedList<>();\n\n    this.applicationStack = new ArrayDeque<>();\n    this.letBindingsStack = new ArrayDeque<>();\n    this.letBindingNamesStack = new ArrayDeque<>();\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/Visitor.java",
    "content": "package org.dhallj.core;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.List;\nimport java.util.Map.Entry;\n\n/**\n * Represents a function from a Dhall expression to a value that recurses through the structure of\n * the expression.\n *\n * @param A The final result type\n */\npublic interface Visitor<A> {\n  void bind(String name, Expr type);\n\n  A onNote(A base, Source source);\n\n  A onNatural(Expr self, BigInteger value);\n\n  A onInteger(Expr self, BigInteger value);\n\n  A onDouble(Expr self, double value);\n\n  A onDate(Expr self, int year, int month, int day);\n\n  A onTime(Expr self, int hour, int minute, int second, BigDecimal fractional);\n\n  A onTimeZone(Expr self, int minutes);\n\n  A onBuiltIn(Expr self, String value);\n\n  A onIdentifier(Expr self, String value, long index);\n\n  A onLambda(String name, A type, A result);\n\n  A onPi(String name, A type, A result);\n\n  A onLet(List<Expr.LetBinding<A>> bindings, A body);\n\n  A onText(String[] parts, List<A> interpolated);\n\n  A onNonEmptyList(List<A> values);\n\n  A onEmptyList(A type);\n\n  A onRecord(List<Entry<String, A>> fields);\n\n  A onRecordType(List<Entry<String, A>> fields);\n\n  A onUnionType(List<Entry<String, A>> fields);\n\n  A onFieldAccess(A base, String fieldName);\n\n  A onProjection(A base, String[] fieldNames);\n\n  A onProjectionByType(A base, A type);\n\n  A onApplication(A base, List<A> args);\n\n  A onOperatorApplication(Operator operator, A lhs, A rhs);\n\n  A onIf(A predicate, A thenValue, A elseValue);\n\n  A onAnnotated(A base, A type);\n\n  A onAssert(A base);\n\n  A onMerge(A handlers, A union, A type);\n\n  A onToMap(A base, A type);\n\n  A onWith(A base, String[] path, A value);\n\n  A onMissingImport(Expr.ImportMode mode, byte[] hash);\n\n  A onEnvImport(String value, Expr.ImportMode mode, byte[] hash);\n\n  A onLocalImport(Path path, Expr.ImportMode mode, byte[] hash);\n\n  A onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash);\n\n  A onRemoteImport(URI url, A using, Expr.ImportMode mode, byte[] hash);\n\n  /** Determines whether the driver sorts fields by name before feeding them to the visitor. */\n  boolean sortFields();\n\n  /**\n   * Determines whether the driver flattens lists matching the {@code toMap} format into records\n   * before feeding them to the visitor.\n   */\n  boolean flattenToMapLists();\n\n  boolean prepareLambda(String name, Expr type);\n\n  boolean preparePi(String name, Expr type);\n\n  boolean prepareLet(int size);\n\n  boolean prepareLetBinding(String name, Expr type);\n\n  boolean prepareText(int size);\n\n  boolean prepareTextPart(String part);\n\n  boolean prepareNonEmptyList(int size);\n\n  boolean prepareNonEmptyListElement(int index);\n\n  boolean prepareEmptyList(Expr type);\n\n  boolean prepareRecord(int size);\n\n  boolean prepareRecordField(String name, Expr type, int index);\n\n  boolean prepareRecordType(int size);\n\n  boolean prepareRecordTypeField(String name, Expr type, int index);\n\n  boolean prepareUnionType(int size);\n\n  boolean prepareUnionTypeField(String name, Expr type, int index);\n\n  boolean prepareFieldAccess(Expr base, String fieldName);\n\n  boolean prepareProjection(int size);\n\n  boolean prepareProjectionByType();\n\n  boolean prepareProjectionByType(Expr type);\n\n  boolean prepareApplication(Expr base, int size);\n\n  boolean prepareOperatorApplication(Operator operator);\n\n  boolean prepareIf();\n\n  boolean prepareAnnotated(Expr type);\n\n  boolean prepareAssert();\n\n  boolean prepareMerge(Expr type);\n\n  boolean prepareToMap(Expr type);\n\n  boolean prepareWith(String[] path);\n\n  boolean prepareWithValue(String[] path);\n\n  boolean prepareRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash);\n\n  /**\n   * Represents a function from a Dhall expression that doesn't need preparation events.\n   *\n   * <p>Note that by default the implementation sees through note layers.\n   *\n   * @param A The result type\n   */\n  public abstract static class NoPrepareEvents<A> implements Visitor<A> {\n\n    public void bind(String name, Expr type) {}\n\n    public boolean sortFields() {\n      return false;\n    }\n\n    public boolean flattenToMapLists() {\n      return false;\n    }\n\n    public boolean prepareLambda(String name, Expr type) {\n      return true;\n    }\n\n    public boolean preparePi(String name, Expr type) {\n      return true;\n    }\n\n    public boolean prepareLet(int size) {\n      return true;\n    }\n\n    public boolean prepareLetBinding(String name, Expr type) {\n      return true;\n    }\n\n    public boolean prepareText(int size) {\n      return true;\n    }\n\n    public boolean prepareTextPart(String part) {\n      return true;\n    }\n\n    public boolean prepareNonEmptyList(int size) {\n      return true;\n    }\n\n    public boolean prepareNonEmptyListElement(int index) {\n      return true;\n    }\n\n    public boolean prepareEmptyList(Expr type) {\n      return true;\n    }\n\n    public boolean prepareRecord(int size) {\n      return true;\n    }\n\n    public boolean prepareRecordField(String name, Expr type, int index) {\n      return true;\n    }\n\n    public boolean prepareRecordType(int size) {\n      return true;\n    }\n\n    public boolean prepareRecordTypeField(String name, Expr type, int index) {\n      return true;\n    }\n\n    public boolean prepareUnionType(int size) {\n      return true;\n    }\n\n    public boolean prepareUnionTypeField(String name, Expr type, int index) {\n      return true;\n    }\n\n    public boolean prepareFieldAccess(Expr base, String fieldName) {\n      return true;\n    }\n\n    public boolean prepareProjection(int size) {\n      return true;\n    }\n\n    public boolean prepareProjectionByType() {\n      return true;\n    }\n\n    public boolean prepareProjectionByType(Expr type) {\n      return true;\n    }\n\n    public boolean prepareApplication(Expr base, int size) {\n      return true;\n    }\n\n    public boolean prepareOperatorApplication(Operator operator) {\n      return true;\n    }\n\n    public boolean prepareIf() {\n      return true;\n    }\n\n    public boolean prepareAnnotated(Expr type) {\n      return true;\n    }\n\n    public boolean prepareAssert() {\n      return true;\n    }\n\n    public boolean prepareMerge(Expr type) {\n      return true;\n    }\n\n    public boolean prepareToMap(Expr type) {\n      return true;\n    }\n\n    public boolean prepareWith(String[] path) {\n      return true;\n    }\n\n    public boolean prepareWithValue(String[] path) {\n      return true;\n    }\n\n    public boolean prepareRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n      return true;\n    }\n\n    /*\n    public A onMissingImport(Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    public A onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    public A onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    public A onRemoteImport(URI url, A using, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }*/\n  }\n\n  /**\n   * Represents a function from a Dhall expression that always returns the same value.\n   *\n   * <p>This is a convenience class designed to help with implementations that have a default value\n   * for most cases.\n   *\n   * <p>Note that by default the implementation sees through note layers.\n   *\n   * @param A The result type\n   */\n  public static class Constant<A> extends NoPrepareEvents<A> {\n    private final A returnValue;\n\n    protected A getReturnValue() {\n      return this.returnValue;\n    }\n\n    public Constant(A value) {\n      this.returnValue = value;\n    }\n\n    public void bind(String name, Expr type) {}\n\n    @Override\n    public A onNote(A base, Source source) {\n      return base;\n    }\n\n    @Override\n    public A onNatural(Expr self, BigInteger value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onInteger(Expr self, BigInteger value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onDouble(Expr self, double value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onDate(Expr self, int year, int month, int day) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onTime(Expr self, int hour, int minute, int second, BigDecimal fractional) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onTimeZone(Expr self, int minutes) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onBuiltIn(Expr self, String value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onIdentifier(Expr self, String value, long index) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onLambda(String name, A type, A result) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onPi(String name, A type, A result) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onLet(List<Expr.LetBinding<A>> bindings, A body) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onText(String[] parts, List<A> interpolated) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onNonEmptyList(List<A> values) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onEmptyList(A type) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onRecord(List<Entry<String, A>> fields) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onRecordType(List<Entry<String, A>> fields) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onUnionType(List<Entry<String, A>> fields) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onFieldAccess(A base, String fieldName) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onProjection(A base, String[] fieldNames) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onProjectionByType(A base, A type) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onApplication(A base, List<A> args) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onOperatorApplication(Operator operator, A lhs, A rhs) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onIf(A predicate, A thenValue, A elseValue) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onAnnotated(A base, A type) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onAssert(A base) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onMerge(A handlers, A union, A type) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onToMap(A base, A type) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onWith(A base, String[] path, A value) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onMissingImport(Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n\n    @Override\n    public A onRemoteImport(URI url, A using, Expr.ImportMode mode, byte[] hash) {\n      return this.getReturnValue();\n    }\n  }\n\n  /**\n   * Represents a property of Dhall expressions.\n   *\n   * <p>This is a convenience class designed to help with implementations that have a default value\n   * for most cases.\n   */\n  public class Property extends Constant<Boolean> {\n    public Property() {\n      super(true);\n    }\n\n    public Boolean onLambda(String name, Boolean type, Boolean result) {\n      return type && result;\n    }\n\n    public Boolean onPi(String name, Boolean type, Boolean result) {\n      return type && result;\n    }\n\n    public Boolean onLet(List<Expr.LetBinding<Boolean>> bindings, Boolean body) {\n      if (!body) {\n        return false;\n      } else {\n        for (Expr.LetBinding<Boolean> binding : bindings) {\n          if (!binding.getValue() || (binding.hasType() && !binding.getType())) {\n            return false;\n          }\n        }\n        return true;\n      }\n    }\n\n    public Boolean onText(String[] parts, List<Boolean> interpolated) {\n      for (Boolean value : interpolated) {\n        if (!value) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public Boolean onNonEmptyList(List<Boolean> values) {\n      for (Boolean value : values) {\n        if (!value) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public Boolean onEmptyList(Boolean type) {\n      return type;\n    }\n\n    public Boolean onRecord(List<Entry<String, Boolean>> fields) {\n      for (Entry<String, Boolean> entry : fields) {\n        if (!entry.getValue()) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public Boolean onRecordType(List<Entry<String, Boolean>> fields) {\n      for (Entry<String, Boolean> entry : fields) {\n        if (!entry.getValue()) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public Boolean onUnionType(List<Entry<String, Boolean>> fields) {\n      for (Entry<String, Boolean> entry : fields) {\n        if (entry.getValue() != null && !entry.getValue()) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public Boolean onFieldAccess(Boolean base, String fieldName) {\n      return base;\n    }\n\n    public Boolean onProjection(Boolean base, String[] fieldNames) {\n      return base;\n    }\n\n    public Boolean onProjectionByType(Boolean base, Boolean type) {\n      return base && type;\n    }\n\n    public Boolean onApplication(Boolean base, List<Boolean> args) {\n      if (!base) {\n        return false;\n      }\n      for (Boolean value : args) {\n        if (!value) {\n          return false;\n        }\n      }\n      return true;\n    }\n\n    public Boolean onOperatorApplication(Operator operator, Boolean lhs, Boolean rhs) {\n      return lhs && rhs;\n    }\n\n    public Boolean onIf(Boolean predicate, Boolean thenValue, Boolean elseValue) {\n      return predicate && thenValue && elseValue;\n    }\n\n    public Boolean onAnnotated(Boolean base, Boolean type) {\n      return base && type;\n    }\n\n    public Boolean onAssert(Boolean base) {\n      return base;\n    }\n\n    public Boolean onMerge(Boolean handlers, Boolean union, Boolean type) {\n      return handlers && union && (type == null || type);\n    }\n\n    public Boolean onToMap(Boolean base, Boolean type) {\n      return base && (type == null || type);\n    }\n\n    public Boolean onToMap(Boolean base, String[] path, Boolean value) {\n      return base && value;\n    }\n\n    public Boolean onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return true;\n    }\n\n    public Boolean onRemoteImport(URI url, Boolean using, Expr.ImportMode mode, byte[] hash) {\n      return true;\n    }\n\n    public Boolean onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n      return true;\n    }\n\n    public Boolean onMissingImport(Expr.ImportMode mode, byte[] hash) {\n      return true;\n    }\n  }\n\n  /**\n   * Represents an identity function.\n   *\n   * <p>This is a convenience class designed to help with implementations that only need to change a\n   * small number of cases.\n   */\n  public abstract class Identity extends NoPrepareEvents<Expr> {\n    public Expr onNote(Expr base, Source source) {\n      return Expr.makeNote(base, source);\n    }\n\n    public Expr onNatural(Expr self, BigInteger value) {\n      return self;\n    }\n\n    public Expr onInteger(Expr self, BigInteger value) {\n      return self;\n    }\n\n    public Expr onDouble(Expr self, double value) {\n      return self;\n    }\n\n    public Expr onDate(Expr self, int year, int month, int day) {\n      return self;\n    }\n\n    public Expr onTime(Expr self, int hour, int minute, int second, BigDecimal fractional) {\n      return self;\n    }\n\n    public Expr onTimeZone(Expr self, int minutes) {\n      return self;\n    }\n\n    public Expr onBuiltIn(Expr self, String name) {\n      return self;\n    }\n\n    public Expr onIdentifier(Expr self, String name, long index) {\n      return self;\n    }\n\n    public Expr onLambda(String name, Expr type, Expr result) {\n      return Expr.makeLambda(name, type, result);\n    }\n\n    public Expr onPi(String name, Expr type, Expr result) {\n      return Expr.makePi(name, type, result);\n    }\n\n    public Expr onLet(List<Expr.LetBinding<Expr>> bindings, Expr body) {\n      return Expr.makeLet(bindings, body);\n    }\n\n    public Expr onText(String[] parts, List<Expr> interpolated) {\n      return Expr.makeTextLiteral(parts, interpolated);\n    }\n\n    public Expr onNonEmptyList(List<Expr> values) {\n      return Expr.makeNonEmptyListLiteral(values);\n    }\n\n    public Expr onEmptyList(Expr type) {\n      return Expr.makeEmptyListLiteral(type);\n    }\n\n    public Expr onRecord(List<Entry<String, Expr>> fields) {\n      return Expr.makeRecordLiteral(fields);\n    }\n\n    public Expr onRecordType(List<Entry<String, Expr>> fields) {\n      return Expr.makeRecordType(fields);\n    }\n\n    public Expr onUnionType(List<Entry<String, Expr>> fields) {\n      return Expr.makeUnionType(fields);\n    }\n\n    public Expr onFieldAccess(Expr base, String fieldName) {\n      return Expr.makeFieldAccess(base, fieldName);\n    }\n\n    public Expr onProjection(Expr base, String[] fieldNames) {\n      return Expr.makeProjection(base, fieldNames);\n    }\n\n    public Expr onProjectionByType(Expr base, Expr type) {\n      return Expr.makeProjectionByType(base, type);\n    }\n\n    public Expr onApplication(Expr base, List<Expr> args) {\n      return Expr.makeApplication(base, args);\n    }\n\n    public Expr onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n      return Expr.makeOperatorApplication(operator, lhs, rhs);\n    }\n\n    public Expr onIf(Expr predicate, Expr thenValue, Expr elseValue) {\n      return Expr.makeIf(predicate, thenValue, elseValue);\n    }\n\n    public Expr onAnnotated(Expr base, Expr type) {\n      return Expr.makeAnnotated(base, type);\n    }\n\n    public Expr onAssert(Expr base) {\n      return Expr.makeAssert(base);\n    }\n\n    public Expr onMerge(Expr handlers, Expr union, Expr type) {\n      return Expr.makeMerge(handlers, union, type);\n    }\n\n    public Expr onToMap(Expr base, Expr type) {\n      return Expr.makeToMap(base, type);\n    }\n\n    public Expr onWith(Expr base, String[] path, Expr value) {\n      return Expr.makeWith(base, path, value);\n    }\n\n    public Expr onMissingImport(Expr.ImportMode mode, byte[] hash) {\n      return Expr.makeMissingImport(mode, hash);\n    }\n\n    public Expr onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n      return Expr.makeEnvImport(value, mode, hash);\n    }\n\n    public Expr onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return Expr.makeLocalImport(path, mode, hash);\n    }\n\n    public Expr onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n      return Expr.makeClasspathImport(path, mode, hash);\n    }\n\n    public Expr onRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n      return Expr.makeRemoteImport(url, using, mode, hash);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/binary/CborDecodingVisitor.java",
    "content": "package org.dhallj.core.binary;\n\nimport org.dhallj.cbor.Reader;\nimport org.dhallj.cbor.Visitor;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Decodes CBOR expressions corresponding to encoded Dhall expressions.\n *\n * <p>Note that e.g. a negative integer by itself is an error, but a single float by itself is\n * allowed.\n */\nfinal class CborDecodingVisitor implements Visitor<Expr> {\n\n  private final Reader reader;\n\n  CborDecodingVisitor(Reader reader) {\n    this.reader = reader;\n  }\n\n  @Override\n  public Expr onUnsignedInteger(BigInteger value) {\n    return Expr.makeIdentifier(\"_\", value.longValue());\n  }\n\n  @Override\n  public Expr onNegativeInteger(BigInteger value) {\n    return notExpected(\"Negative integer \" + value);\n  }\n\n  @Override\n  public Expr onByteString(byte[] value) {\n    return notExpected(\"ByteString\");\n  }\n\n  @Override\n  public Expr onTextString(String value) {\n    return Expr.makeBuiltIn(value);\n  }\n\n  @Override\n  public Expr onVariableArray(BigInteger length, String name) {\n    if (length.intValue() != 2) {\n      throw new DecodingException(\"Variables must be encoded in an array of length 2\");\n    } else if (name.equals(\"_\")) {\n      throw new DecodingException(\"Variables cannot be explicitly named _\");\n    } else {\n      BigInteger idx = this.reader.readPositiveBigNum();\n      return Expr.makeIdentifier(name, idx.longValue());\n    }\n  }\n\n  @Override\n  public Expr onArray(BigInteger length, BigInteger tagI) {\n    int tag = tagI.intValue();\n\n    switch (tag) {\n      case Label.APPLICATION:\n        return readFnApplication(length);\n      case Label.LAMBDA:\n        return readFunction(length);\n      case Label.PI:\n        return readPi(length);\n      case Label.OPERATOR_APPLICATION:\n        return readOperator(length);\n      case Label.LIST:\n        return readList(length);\n      case Label.SOME:\n        return readSome(length);\n      case Label.MERGE:\n        return readMerge(length);\n      case Label.RECORD_TYPE:\n        return readRecordType(length);\n      case Label.RECORD_LITERAL:\n        return readRecordLiteral(length);\n      case Label.FIELD_ACCESS:\n        return readFieldAccess(length);\n      case Label.PROJECTION:\n        return readProjection(length);\n      case Label.UNION_TYPE:\n        return readUnion(length);\n      case Label.IF:\n        return readIf(length);\n      case Label.NATURAL:\n        return readNatural(length);\n      case Label.INTEGER:\n        return readInteger(length);\n      case Label.TEXT:\n        return readTextLiteral(length);\n      case Label.ASSERT:\n        return readAssert(length);\n      case Label.IMPORT:\n        return readImport(length);\n      case Label.LET:\n        return readLet(length);\n      case Label.ANNOTATED:\n        return readTypeAnnotation(length);\n      case Label.TO_MAP:\n        return readMap(length);\n      case Label.EMPTY_LIST_WITH_ABSTRACT_TYPE:\n        return readEmptyListAbstractType(length);\n      case Label.DATE:\n        return readDate(length);\n      case Label.TIME:\n        return readTime(length);\n      case Label.TIME_ZONE:\n        return readTimeZone(length);\n      default:\n        throw new DecodingException(\"Array tag \" + Integer.toString(tag) + \" undefined\");\n    }\n  }\n\n  @Override\n  public Expr onMap(BigInteger size) {\n    return notExpected(\"Map\");\n  }\n\n  @Override\n  public Expr onFalse() {\n    return Expr.Constants.FALSE;\n  }\n\n  @Override\n  public Expr onTrue() {\n    return Expr.Constants.TRUE;\n  }\n\n  @Override\n  public Expr onNull() {\n    return null;\n  }\n\n  @Override\n  public Expr onHalfFloat(float value) {\n    return Expr.makeDoubleLiteral(value);\n  }\n\n  @Override\n  public Expr onSingleFloat(float value) {\n    return Expr.makeDoubleLiteral(value);\n  }\n\n  @Override\n  public Expr onDoubleFloat(double value) {\n    return Expr.makeDoubleLiteral(value);\n  }\n\n  @Override\n  public Expr onTag() {\n    // TODO\n    return notExpected(\"Tag\");\n  }\n\n  private Expr readFnApplication(BigInteger length) {\n    if (length.longValue() < 3) {\n      throw new DecodingException(\"Function application must have at least one argument\");\n    }\n    Expr fn = readExpr();\n    ArrayList<Expr> args = new ArrayList<>();\n    for (int i = 0; i < length.longValue() - 2; i++) {\n      Expr arg = readExpr();\n      args.add(arg);\n    }\n    return Expr.makeApplication(fn, args);\n  }\n\n  private Expr readFunction(BigInteger length) {\n    long len = length.longValue();\n    if (len == 3) {\n      Expr tpe = readExpr();\n      Expr result = readExpr();\n      return Expr.makeLambda(\"_\", tpe, result);\n    } else if (len == 4) {\n      String param = this.reader.readNullableTextString();\n      if (param.equals(\"_\")) {\n        throw new DecodingException((\"Illegal explicit bound variable '_' in function\"));\n      }\n      Expr tpe = readExpr();\n      Expr resultTpe = readExpr();\n      return Expr.makeLambda(param, tpe, resultTpe);\n    } else {\n      throw new DecodingException(\"Function types must be encoded in an array of length 3 or 4\");\n    }\n  }\n\n  private Expr readPi(BigInteger length) {\n    long len = length.longValue();\n    if (len == 3) {\n      Expr tpe = readExpr();\n      Expr resultTpe = readExpr();\n      return Expr.makePi(tpe, resultTpe);\n    } else if (len == 4) {\n      String param = this.reader.readNullableTextString();\n      if (param.equals(\"_\")) {\n        throw new DecodingException((\"Illegal explicit bound variable '_' in pi type\"));\n      }\n      Expr tpe = readExpr();\n      Expr resultTpe = readExpr();\n      return Expr.makePi(param, tpe, resultTpe);\n    } else {\n      throw new DecodingException(\"Pi types must be encoded in an array of length 3 or 4\");\n    }\n  }\n\n  private Expr readOperator(BigInteger length) {\n    if (length.longValue() != 4) {\n      throw new DecodingException(\"Operator application must be encoded in an array of length 4\");\n    }\n    int operatorLabel = this.reader.readUnsignedInteger().intValue();\n    Expr lhs = readExpr();\n    Expr rhs = readExpr();\n\n    Operator operator = Operator.fromLabel(operatorLabel);\n\n    if (operator != null) {\n      return Expr.makeOperatorApplication(operator, lhs, rhs);\n    } else {\n      throw new DecodingException(\n          \"Operator tag \" + Integer.toString(operatorLabel) + \" is undefined\");\n    }\n  }\n\n  private Expr readList(BigInteger length) {\n    Expr tpe = readExpr();\n    if (length.intValue() == 2) {\n      if (tpe == null) {\n        throw new DecodingException(\"Type must be specified if list is empty\");\n      } else {\n        return Expr.makeEmptyListLiteral(Expr.makeApplication(Expr.Constants.LIST, tpe));\n      }\n    } else {\n      if (tpe == null) {\n        List<Expr> exprs = new ArrayList<>();\n        for (int i = 2; i < length.longValue(); i++) {\n          exprs.add(readExpr());\n        }\n        return Expr.makeNonEmptyListLiteral(exprs);\n      } else {\n        throw new DecodingException(\"Non-empty lists must not have a type annotation\");\n      }\n    }\n  }\n\n  private Expr readEmptyListAbstractType(BigInteger length) {\n    Expr tpe = readExpr();\n    if (length.intValue() == 2) {\n      if (tpe == null) {\n        throw new DecodingException(\"Type must be specified if list is empty\");\n      } else {\n        return Expr.makeEmptyListLiteral(tpe);\n      }\n    } else {\n      throw new DecodingException(\"List of abstract type must be empty\");\n    }\n  }\n\n  private Expr readSome(BigInteger length) {\n    int len = length.intValue();\n    if (len != 3) {\n      throw new DecodingException(\"Some must be encoded in an array of length 3\");\n    } else {\n      // The spec currently says \"Some expressions store the type (if present) and their value\", but\n      // we ignore the type, and (I think) it should always be null.\n      readExpr();\n      Expr value = readExpr();\n      return Expr.makeApplication(Expr.Constants.SOME, value);\n    }\n  }\n\n  private Expr readMerge(BigInteger length) {\n    int len = length.intValue();\n    if (len == 3) {\n      Expr l = readExpr();\n      Expr r = readExpr();\n      return Expr.makeMerge(l, r);\n    } else if (len == 4) {\n      Expr l = readExpr();\n      Expr r = readExpr();\n      Expr tpe = readExpr();\n      return Expr.makeMerge(l, r, tpe);\n    } else {\n      throw new DecodingException(\"Merge must be encoded in an array of length 3 or 4\");\n    }\n  }\n\n  private Expr readMap(BigInteger length) {\n    int len = length.intValue();\n    if (len == 2) {\n      Expr e = readExpr();\n      return Expr.makeToMap(e);\n    } else if (len == 3) {\n      Expr e = readExpr();\n      Expr tpe = readExpr();\n      return Expr.makeToMap(e, tpe);\n    } else {\n      throw new DecodingException(\"ToMap must be encoded in an array of length 2 or 3\");\n    }\n  }\n\n  private Expr readWith(BigInteger length) {\n    int len = length.intValue();\n    if (len == 4) {\n      Expr base = readExpr();\n      int pathLen = this.reader.readArrayStart().intValue();\n      String[] path = new String[pathLen];\n\n      for (int i = 0; i < pathLen; i += 1) {\n        path[i] = this.reader.readNullableTextString();\n      }\n\n      Expr value = readExpr();\n      return Expr.makeWith(base, path, value);\n    } else {\n      throw new DecodingException(\"with must be encoded in an array of length 4\");\n    }\n  }\n\n  private Expr readRecordType(BigInteger length) {\n    long len = length.longValue();\n    if (len != 2) {\n      throw new DecodingException(\"Record literal must be encoded in an array of length 2\");\n    } else {\n      Map<String, Expr> entries = this.reader.readMap(this);\n      return Expr.makeRecordType(entries.entrySet());\n    }\n  }\n\n  private Expr readRecordLiteral(BigInteger length) {\n    long len = length.longValue();\n    if (len != 2) {\n      throw new DecodingException(\"Record literal must be encoded in an array of length 2\");\n    } else {\n      Map<String, Expr> entries = this.reader.readMap(this);\n      return Expr.makeRecordLiteral(entries.entrySet());\n    }\n  }\n\n  private Expr readFieldAccess(BigInteger length) {\n    int len = length.intValue();\n    if (len != 3) {\n      throw new DecodingException(\"Field access must be encoded in array of length 3\");\n    } else {\n      Expr e = readExpr();\n      String field = this.reader.readNullableTextString();\n      return Expr.makeFieldAccess(e, field);\n    }\n  }\n\n  private Expr readProjection(BigInteger length) {\n    long len = length.longValue();\n    Expr e = readExpr();\n    if (len == 2) {\n      return Expr.makeProjection(e, new String[0]);\n    } else {\n      // This is horrible but so is the encoding of record projections - we don't know whether\n      // we expect an array or Strings next\n      String first = this.reader.tryReadTextString();\n      if (first != null) {\n        List<String> fields = new ArrayList<>();\n        fields.add(first);\n        for (int i = 3; i < len; i++) {\n          fields.add(this.reader.tryReadTextString());\n        }\n        return Expr.makeProjection(e, fields.toArray(new String[fields.size()]));\n      } else {\n        // It was actually an array\n        int innerLen = this.reader.readArrayStart().intValue();\n        if (innerLen != 1) {\n          throw new DecodingException(\n              \"Type for type  projection must be encoded in an array of length 1\");\n        } else {\n          Expr tpe = readExpr();\n          return Expr.makeProjectionByType(e, tpe);\n        }\n      }\n    }\n  }\n\n  private Expr readUnion(BigInteger length) {\n    int len = length.intValue();\n    if (len != 2) {\n      throw new DecodingException(\"Union must be encoded in array of length 2\");\n    } else {\n      Map<String, Expr> entries = this.reader.readMap(this);\n      return Expr.makeUnionType(entries.entrySet());\n    }\n  }\n\n  private Expr readIf(BigInteger length) {\n    int len = length.intValue();\n    if (len != 4) {\n      throw new DecodingException(\"If must be encoded in an array of length 4\");\n    } else {\n      Expr cond = readExpr();\n      Expr ifE = readExpr();\n      Expr elseE = readExpr();\n      return Expr.makeIf(cond, ifE, elseE);\n    }\n  }\n\n  private Expr readTypeAnnotation(BigInteger length) {\n    int len = length.intValue();\n    if (len != 3) {\n      throw new DecodingException(\"Type annotation must be encoded in array of length 3\");\n    } else {\n      Expr e = readExpr();\n      Expr tpe = readExpr();\n      return Expr.makeAnnotated(e, tpe);\n    }\n  }\n\n  private Expr readLet(BigInteger length) {\n    return readLet(length.longValue());\n  }\n\n  private Expr readLet(long len) {\n    if (len == 5) {\n      String name = this.reader.readNullableTextString();\n      Expr tpe = readExpr();\n      Expr value = readExpr();\n      Expr body = readExpr();\n      return Expr.makeLet(name, tpe, value, body);\n    } else {\n      String name = this.reader.readNullableTextString();\n      Expr tpe = readExpr();\n      Expr value = readExpr();\n      return Expr.makeLet(name, tpe, value, readLet(len - 3));\n    }\n  }\n\n  private Expr readImport(BigInteger length) {\n    byte[] hash = this.reader.readNullableByteString();\n    Expr.ImportMode mode = readMode();\n    int tag = this.reader.readUnsignedInteger().intValue();\n\n    switch (tag) {\n      case Label.IMPORT_TYPE_REMOTE_HTTP:\n        Expr httpUsing = readExpr();\n        return readRemoteImport(length, mode, hash, \"http:/\", httpUsing);\n      case Label.IMPORT_TYPE_REMOTE_HTTPS:\n        Expr httpsUsing = readExpr();\n        return readRemoteImport(length, mode, hash, \"https:/\", httpsUsing);\n      case Label.IMPORT_TYPE_LOCAL_ABSOLUTE:\n        return readLocalImport(length, mode, hash, \"/\");\n      case Label.IMPORT_TYPE_LOCAL_HERE:\n        return readLocalImport(length, mode, hash, \"./\");\n      case Label.IMPORT_TYPE_LOCAL_PARENT:\n        return readLocalImport(length, mode, hash, \"../\");\n      case Label.IMPORT_TYPE_LOCAL_HOME:\n        return readLocalImport(length, mode, hash, \"~\");\n      case Label.IMPORT_TYPE_ENV:\n        return readEnvImport(length, mode, hash);\n      case Label.IMPORT_TYPE_MISSING:\n        return Expr.makeMissingImport(mode, hash);\n      case Label.IMPORT_TYPE_CLASSPATH:\n        return readClasspathImport(length, mode, hash, \"/\");\n      default:\n        throw new DecodingException(\"Import type \" + Integer.toString(tag) + \" is undefined\");\n    }\n  }\n\n  private Expr.ImportMode readMode() {\n    int m = this.reader.readUnsignedInteger().intValue();\n    if (m == 0) {\n      return Expr.ImportMode.CODE;\n    } else if (m == 1) {\n      return Expr.ImportMode.RAW_TEXT;\n    } else if (m == 2) {\n      return Expr.ImportMode.LOCATION;\n    } else {\n      throw new DecodingException(\"Import mode \" + Integer.toString(m) + \" is undefined\");\n    }\n  }\n\n  private Expr readLocalImport(\n      BigInteger length, Expr.ImportMode mode, byte[] hash, String prefix) {\n    Path path = Paths.get(prefix);\n    int len = length.intValue();\n    for (int i = 4; i < len; i++) {\n      path = path.resolve(this.reader.readNullableTextString());\n    }\n    return Expr.makeLocalImport(path, mode, hash);\n  }\n\n  private Expr readClasspathImport(\n      BigInteger length, Expr.ImportMode mode, byte[] hash, String prefix) {\n    Path path = Paths.get(prefix);\n    int len = length.intValue();\n    for (int i = 4; i < len; i++) {\n      path = path.resolve(this.reader.readNullableTextString());\n    }\n    return Expr.makeClasspathImport(path, mode, hash);\n  }\n\n  private Expr readRemoteImport(\n      BigInteger length, Expr.ImportMode mode, byte[] hash, String prefix, Expr using) {\n    StringBuilder builder = new StringBuilder(prefix);\n    int len = length.intValue();\n    for (int i = 5; i < len - 1; i++) {\n      builder.append(\"/\");\n      builder.append(this.reader.readNullableTextString());\n    }\n    String query = this.reader.readNullableTextString();\n    if (query != null) {\n      builder.append(\"?\");\n      builder.append(query);\n    }\n    try {\n      return Expr.makeRemoteImport(new URI(builder.toString()), using, mode, hash);\n    } catch (URISyntaxException cause) {\n      throw new DecodingException(\"Invalid URL in remote import\", cause);\n    }\n  }\n\n  private Expr readEnvImport(BigInteger length, Expr.ImportMode mode, byte[] hash) {\n    String value = this.reader.readNullableTextString();\n    return Expr.makeEnvImport(value, mode, hash);\n  }\n\n  private Expr readAssert(BigInteger length) {\n    long len = length.longValue();\n    if (len != 2) {\n      throw new DecodingException(\"Assert must be encoded in array of length 2\");\n    } else {\n      Expr e = readExpr();\n      return Expr.makeAssert(e);\n    }\n  }\n\n  private Expr readTextLiteral(BigInteger length) {\n    List<String> lits = new ArrayList<>();\n    List<Expr> exprs = new ArrayList<>();\n    String lit = this.reader.readNullableTextString();\n    lits.add(lit);\n    for (int i = 2; i < length.longValue(); i += 2) {\n      Expr e = readExpr();\n      exprs.add(e);\n      lit = this.reader.readNullableTextString();\n      lits.add(lit);\n    }\n    return Expr.makeTextLiteral(lits.toArray(new String[0]), exprs.toArray(new Expr[0]));\n  }\n\n  private Expr readInteger(BigInteger length) {\n    return Expr.makeIntegerLiteral(this.reader.readBigNum());\n  }\n\n  private Expr readNatural(BigInteger length) {\n    return Expr.makeNaturalLiteral(this.reader.readPositiveBigNum());\n  }\n\n  private Expr readDate(BigInteger length) {\n    long len = length.longValue();\n    if (len != 4) {\n      throw new DecodingException(\"Date must be encoded in array of length 4\");\n    } else {\n      BigInteger year = this.reader.readUnsignedInteger();\n      BigInteger month = this.reader.readUnsignedInteger();\n      BigInteger day = this.reader.readUnsignedInteger();\n      return Expr.makeDateLiteral(year.intValue(), month.intValue(), day.intValue());\n    }\n  }\n\n  private Expr readTime(BigInteger length) {\n    long len = length.longValue();\n    if (len != 4) {\n      throw new DecodingException(\"Time zone must be encoded in array of length 4\");\n    } else {\n      BigInteger hour = this.reader.readUnsignedInteger();\n      BigInteger minute = this.reader.readUnsignedInteger();\n      BigDecimal rawSeconds = this.reader.readBigDecimal();\n      int seconds = rawSeconds.intValue();\n      BigDecimal fractional = rawSeconds.subtract(new BigDecimal(seconds));\n\n      return Expr.makeTimeLiteral(hour.intValue(), minute.intValue(), seconds, fractional);\n    }\n  }\n\n  private Expr readTimeZone(BigInteger length) {\n    long len = length.longValue();\n    if (len != 4) {\n      throw new DecodingException(\"Time zone must be encoded in array of length 4\");\n    } else {\n      boolean positive = readExpr() != Expr.Constants.FALSE;\n      BigInteger hour = this.reader.readUnsignedInteger();\n      BigInteger minute = this.reader.readUnsignedInteger();\n\n      int value = hour.intValue() * 60 + minute.intValue();\n\n      if (!positive) {\n        value = -value;\n      }\n\n      return Expr.makeTimeZoneLiteral(value);\n    }\n  }\n\n  private Expr readExpr() {\n    return this.reader.nextSymbol(this);\n  }\n\n  private Expr notExpected(String msg) {\n    throw new DecodingException(\n        \"Expected String or UnsignedInteger as first element of array. Found \" + msg);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/binary/Decode.java",
    "content": "package org.dhallj.core.binary;\n\nimport org.dhallj.cbor.Reader;\nimport org.dhallj.core.Expr;\n\npublic class Decode {\n  public static final Expr decode(byte[] bytes) {\n    Reader reader = new Reader.ByteArrayReader(bytes);\n    // TODO check: if identifier then must be builtin using Expr.Constants.isBuiltInConstant\n    Expr e = reader.nextSymbol(new CborDecodingVisitor(reader));\n    return e;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/binary/DecodingException.java",
    "content": "package org.dhallj.core.binary;\n\nimport org.dhallj.core.DhallException;\n\npublic class DecodingException extends DhallException {\n  public DecodingException(String message) {\n    super(message);\n  }\n\n  public DecodingException(String message, Throwable cause) {\n    super(message, cause);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/binary/Encode.java",
    "content": "package org.dhallj.core.binary;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.cbor.Writer;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Source;\nimport org.dhallj.core.Visitor;\n\npublic final class Encode implements Visitor<Void> {\n  private final Writer writer;\n\n  public Encode(Writer writer) {\n    this.writer = writer;\n  }\n\n  public boolean sortFields() {\n    return true;\n  }\n\n  public boolean flattenToMapLists() {\n    return false;\n  }\n\n  public Void onNote(Void base, Source source) {\n    return base;\n  }\n\n  public Void onNatural(Expr self, BigInteger value) {\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(Label.NATURAL);\n    this.writer.writeBigInteger(value);\n    return null;\n  }\n\n  public Void onInteger(Expr self, BigInteger value) {\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(Label.INTEGER);\n    this.writer.writeBigInteger(value);\n    return null;\n  }\n\n  public Void onDouble(Expr self, double value) {\n    this.writer.writeDouble(value);\n    return null;\n  }\n\n  public Void onDate(Expr self, int year, int month, int day) {\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.DATE);\n    this.writer.writeLong(year);\n    this.writer.writeLong(month);\n    this.writer.writeLong(day);\n    return null;\n  }\n\n  public Void onTime(Expr self, int hour, int minute, int second, BigDecimal fractional) {\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.TIME);\n    this.writer.writeLong(hour);\n    this.writer.writeLong(minute);\n    this.writer.writeBigDecimal(fractional.add(BigDecimal.valueOf(second)));\n    return null;\n  }\n\n  public Void onTimeZone(Expr self, int minutes) {\n    boolean sign = minutes >= 0;\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.TIME_ZONE);\n    this.writer.writeBoolean(sign);\n    int m = Math.abs(minutes);\n    this.writer.writeLong(m / 60);\n    this.writer.writeLong(m % 60);\n    return null;\n  }\n\n  public Void onBuiltIn(Expr self, String name) {\n    if (name.equals(\"True\")) {\n      this.writer.writeBoolean(true);\n    } else if (name.equals(\"False\")) {\n      this.writer.writeBoolean(false);\n    } else {\n      this.writer.writeString(name);\n    }\n    return null;\n  }\n\n  public Void onIdentifier(Expr self, String name, long index) {\n    if (name.equals(\"_\")) {\n      this.writer.writeLong(index);\n    } else {\n      this.writer.writeArrayStart(2);\n      this.writer.writeString(name);\n      this.writer.writeLong(index);\n    }\n    return null;\n  }\n\n  public void bind(String param, Expr type) {}\n\n  public boolean prepareLambda(String name, Expr type) {\n    if (name.equals(\"_\")) {\n      this.writer.writeArrayStart(3);\n      this.writer.writeLong(Label.LAMBDA);\n    } else {\n      this.writer.writeArrayStart(4);\n      this.writer.writeLong(Label.LAMBDA);\n      this.writer.writeString(name);\n    }\n    return true;\n  }\n\n  public Void onLambda(String name, Void type, Void result) {\n    return null;\n  }\n\n  public boolean preparePi(String name, Expr type) {\n    if (name.equals(\"_\")) {\n      this.writer.writeArrayStart(3);\n      this.writer.writeLong(Label.PI);\n    } else {\n      this.writer.writeArrayStart(4);\n      this.writer.writeLong(Label.PI);\n      this.writer.writeString(name);\n    }\n    return true;\n  }\n\n  public Void onPi(String name, Void type, Void result) {\n    return null;\n  }\n\n  public boolean prepareLet(int size) {\n    this.writer.writeArrayStart(2 + size * 3);\n    this.writer.writeLong(Label.LET);\n    return true;\n  }\n\n  public boolean prepareLetBinding(String name, Expr type) {\n    this.writer.writeString(name);\n    if (type == null) {\n      this.writer.writeNull();\n    }\n    return true;\n  }\n\n  public Void onLet(List<Expr.LetBinding<Void>> bindings, Void body) {\n    return null;\n  }\n\n  private static final String unescapeText(String input) {\n    StringBuilder builder = new StringBuilder();\n\n    for (int i = 0; i < input.length(); i += 1) {\n      if (input.charAt(i) == '\\\\') {\n        i += 1;\n        char next = input.charAt(i);\n\n        if (next == '\"') {\n          builder.append('\"');\n        } else if (next == '\\\\') {\n          builder.append('\\\\');\n        } else if (next == 'b') {\n          builder.append('\\b');\n        } else if (next == 'f') {\n          builder.append('\\f');\n        } else if (next == 'n') {\n          builder.append('\\n');\n        } else if (next == 'r') {\n          builder.append('\\r');\n        } else if (next == 't') {\n          builder.append('\\t');\n        } else {\n          builder.append('\\\\');\n          builder.append(next);\n        }\n      } else {\n        builder.append(input.charAt(i));\n      }\n    }\n\n    return builder.toString();\n  }\n\n  public boolean prepareText(int size) {\n    this.writer.writeArrayStart(size * 2);\n    this.writer.writeLong(Label.TEXT);\n    return true;\n  }\n\n  public boolean prepareTextPart(String part) {\n    this.writer.writeString(unescapeText(part));\n    return true;\n  }\n\n  public Void onText(String[] parts, List<Void> interpolated) {\n    return null;\n  }\n\n  public boolean prepareNonEmptyList(int size) {\n    this.writer.writeArrayStart(size + 2);\n    this.writer.writeLong(Label.LIST);\n    this.writer.writeNull();\n    return true;\n  }\n\n  public boolean prepareNonEmptyListElement(int index) {\n    return true;\n  }\n\n  public Void onNonEmptyList(final List<Void> values) {\n    return null;\n  }\n\n  public boolean prepareEmptyList(Expr type) {\n    final Expr listElementType = Expr.Util.getListArg(type);\n\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(\n        (listElementType != null) ? Label.LIST : Label.EMPTY_LIST_WITH_ABSTRACT_TYPE);\n\n    if (listElementType != null) {\n      // We have to recurse explicitly.\n      listElementType.accept(this);\n      return false;\n    } else {\n      return true;\n    }\n  }\n\n  public Void onEmptyList(Void type) {\n    return null;\n  }\n\n  public boolean prepareRecord(int size) {\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(Label.RECORD_LITERAL);\n    this.writer.writeMapStart(size);\n    return true;\n  }\n\n  public boolean prepareRecordField(String name, Expr type, int index) {\n    this.writer.writeString(name);\n    return true;\n  }\n\n  public Void onRecord(final List<Entry<String, Void>> fields) {\n    return null;\n  }\n\n  public boolean prepareRecordType(int size) {\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(Label.RECORD_TYPE);\n    this.writer.writeMapStart(size);\n    return true;\n  }\n\n  public boolean prepareRecordTypeField(String name, Expr type, int index) {\n    this.writer.writeString(name);\n    return true;\n  }\n\n  public Void onRecordType(final List<Entry<String, Void>> fields) {\n    return null;\n  }\n\n  public boolean prepareUnionType(int size) {\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(Label.UNION_TYPE);\n    this.writer.writeMapStart(size);\n    return true;\n  }\n\n  public boolean prepareUnionTypeField(String name, Expr type, int index) {\n    this.writer.writeString(name);\n    if (type == null) {\n      this.writer.writeNull();\n    }\n    return true;\n  }\n\n  public Void onUnionType(final List<Entry<String, Void>> fields) {\n    return null;\n  }\n\n  public boolean prepareFieldAccess(Expr base, String fieldName) {\n    this.writer.writeArrayStart(3);\n    this.writer.writeLong(Label.FIELD_ACCESS);\n    return true;\n  }\n\n  public Void onFieldAccess(Void base, final String fieldName) {\n    this.writer.writeString(fieldName);\n    return null;\n  }\n\n  public boolean prepareProjection(int size) {\n    this.writer.writeArrayStart(size + 2);\n    this.writer.writeLong(Label.PROJECTION);\n    return true;\n  }\n\n  public Void onProjection(Void base, final String[] fieldNames) {\n    for (String fieldName : fieldNames) {\n      this.writer.writeString(fieldName);\n    }\n    return null;\n  }\n\n  public boolean prepareProjectionByType() {\n    this.writer.writeArrayStart(3);\n    this.writer.writeLong(Label.PROJECTION);\n    return true;\n  }\n\n  public boolean prepareProjectionByType(Expr type) {\n    this.writer.writeArrayStart(1);\n    return true;\n  }\n\n  public Void onProjectionByType(Void base, Void type) {\n    return null;\n  }\n\n  public boolean prepareApplication(Expr base, int size) {\n    String asBuiltIn = Expr.Util.asBuiltIn(base);\n\n    if (asBuiltIn != null && asBuiltIn.equals(\"Some\")) {\n      /**\n       * This is a kind of weird case that I don't think should ever occur in well-typed code, but\n       * we need this special casing to pass the {@code SomeXYZ} parser test.\n       */\n      if (size > 1) {\n        this.writer.writeArrayStart(size + 1);\n        this.writer.writeLong(Label.APPLICATION);\n      }\n      this.writer.writeArrayStart(3);\n      this.writer.writeLong(Label.SOME);\n      this.writer.writeNull();\n      return false;\n    } else {\n      this.writer.writeArrayStart(size + 2);\n      this.writer.writeLong(Label.APPLICATION);\n      return true;\n    }\n  }\n\n  public Void onApplication(Void base, final List<Void> args) {\n    return null;\n  }\n\n  public boolean prepareOperatorApplication(final Operator operator) {\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.OPERATOR_APPLICATION);\n    this.writer.writeLong(operator.getLabel());\n    return true;\n  }\n\n  public Void onOperatorApplication(Operator operator, Void lhs, Void rhs) {\n    return null;\n  }\n\n  public boolean prepareIf() {\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.IF);\n    return true;\n  }\n\n  public Void onIf(Void predicate, Void thenValue, Void elseValue) {\n    return null;\n  }\n\n  public boolean prepareAnnotated(Expr type) {\n    this.writer.writeArrayStart(3);\n    this.writer.writeLong(Label.ANNOTATED);\n    return true;\n  }\n\n  public Void onAnnotated(Void base, Void type) {\n    return null;\n  }\n\n  public boolean prepareAssert() {\n    this.writer.writeArrayStart(2);\n    this.writer.writeLong(Label.ASSERT);\n    return true;\n  }\n\n  public Void onAssert(Void base) {\n    return null;\n  }\n\n  public boolean prepareMerge(Expr type) {\n    this.writer.writeArrayStart((type == null) ? 3 : 4);\n    this.writer.writeLong(Label.MERGE);\n    return true;\n  }\n\n  public Void onMerge(Void handlers, Void union, Void type) {\n    return null;\n  }\n\n  public boolean prepareToMap(Expr type) {\n    this.writer.writeArrayStart((type == null) ? 2 : 3);\n    this.writer.writeLong(Label.TO_MAP);\n    return true;\n  }\n\n  public Void onToMap(Void base, Void type) {\n    return null;\n  }\n\n  public boolean prepareWith(String[] path) {\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.WITH);\n    return true;\n  }\n\n  public boolean prepareWithValue(String[] path) {\n    this.writer.writeArrayStart(path.length);\n    for (int i = 0; i < path.length; i += 1) {\n      this.writer.writeString(path[i]);\n    }\n    return true;\n  }\n\n  public Void onWith(Void base, String[] path, Void value) {\n    return null;\n  }\n\n  private final int modeLabel(Expr.ImportMode mode) {\n    if (mode.equals(Expr.ImportMode.RAW_TEXT)) {\n      return 1;\n    } else if (mode.equals(Expr.ImportMode.LOCATION)) {\n      return 2;\n    } else {\n      return 0;\n    }\n  }\n\n  private static final byte[] multihash(byte[] hash) {\n    byte[] bytes = new byte[34];\n    // The label for SHA-256.\n    bytes[0] = 18;\n    // The digest size.\n    bytes[1] = 32;\n    System.arraycopy(hash, 0, bytes, 2, 32);\n    return bytes;\n  }\n\n  public Void onMissingImport(final Expr.ImportMode mode, final byte[] hash) {\n    this.writer.writeArrayStart(4);\n    this.writer.writeLong(Label.IMPORT);\n    if (hash == null) {\n      this.writer.writeNull();\n    } else {\n      this.writer.writeByteString(multihash(hash));\n    }\n    this.writer.writeLong(modeLabel(mode));\n    this.writer.writeLong(Label.IMPORT_TYPE_MISSING);\n    return null;\n  }\n\n  public Void onEnvImport(final String value, final Expr.ImportMode mode, final byte[] hash) {\n    this.writer.writeArrayStart(5);\n    this.writer.writeLong(Label.IMPORT);\n    if (hash == null) {\n      this.writer.writeNull();\n    } else {\n      this.writer.writeByteString(multihash(hash));\n    }\n    this.writer.writeLong(modeLabel(mode));\n    this.writer.writeLong(Label.IMPORT_TYPE_ENV);\n    this.writer.writeString(value);\n    return null;\n  }\n\n  private static final int pathLabel(Path path) {\n    if (path.isAbsolute()) {\n      return Label.IMPORT_TYPE_LOCAL_ABSOLUTE;\n    } else {\n      String first = path.iterator().next().toString();\n      if (first.equals(\".\")) {\n        return Label.IMPORT_TYPE_LOCAL_HERE;\n      } else if (first.equals(\"..\")) {\n        return Label.IMPORT_TYPE_LOCAL_PARENT;\n      } else if (first.equals(\"~\")) {\n        return Label.IMPORT_TYPE_LOCAL_HOME;\n      }\n    }\n    return -1;\n  }\n\n  public Void onLocalImport(final Path path, final Expr.ImportMode mode, final byte[] hash) {\n    int size = 4 + path.getNameCount() - (path.isAbsolute() ? 0 : 1);\n    this.writer.writeArrayStart(size);\n    this.writer.writeLong(Label.IMPORT);\n    if (hash == null) {\n      this.writer.writeNull();\n    } else {\n      this.writer.writeByteString(multihash(hash));\n    }\n    this.writer.writeLong(modeLabel(mode));\n    this.writer.writeLong(pathLabel(path));\n\n    Iterator<Path> parts = path.iterator();\n    if (!path.isAbsolute()) {\n      parts.next();\n    }\n    while (parts.hasNext()) {\n      this.writer.writeString(parts.next().toString());\n    }\n    return null;\n  }\n\n  @Override\n  public Void onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    int size = 4 + path.getNameCount();\n    this.writer.writeArrayStart(size);\n    this.writer.writeLong(Label.IMPORT);\n    if (hash == null) {\n      this.writer.writeNull();\n    } else {\n      this.writer.writeByteString(multihash(hash));\n    }\n    this.writer.writeLong(modeLabel(mode));\n    this.writer.writeLong(Label.IMPORT_TYPE_CLASSPATH);\n\n    Iterator<Path> parts = path.iterator();\n    while (parts.hasNext()) {\n      this.writer.writeString(parts.next().toString());\n    }\n    return null;\n  }\n\n  private static final int urlLabel(URI url) {\n    if (url.getScheme().equals(\"https\")) {\n      return Label.IMPORT_TYPE_REMOTE_HTTPS;\n    } else if (url.getScheme().equals(\"http\")) {\n      return Label.IMPORT_TYPE_REMOTE_HTTP;\n    } else {\n      return -1;\n    }\n  }\n\n  private static final List<String> getUrlPathParts(URI url) {\n    final List<String> parts = new ArrayList<String>();\n    // TODO: verify that we don't need the raw versions here (currently escaped octets are decoded).\n    parts.add(url.getAuthority());\n\n    String[] pathParts = url.getPath().split(\"/\");\n\n    if (pathParts.length == 1) {\n      parts.add(\"\");\n    } else {\n      for (int i = 1; i < pathParts.length; i++) {\n        parts.add(pathParts[i]);\n      }\n    }\n\n    return parts;\n  }\n\n  public boolean prepareRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n    final List<String> parts = getUrlPathParts(url);\n\n    this.writer.writeArrayStart(parts.size() + 6);\n    this.writer.writeLong(Label.IMPORT);\n    if (hash == null) {\n      this.writer.writeNull();\n    } else {\n      this.writer.writeByteString(multihash(hash));\n    }\n    this.writer.writeLong(modeLabel(mode));\n    this.writer.writeLong(urlLabel(url));\n\n    if (using == null) {\n      this.writer.writeNull();\n    }\n    return true;\n  }\n\n  public Void onRemoteImport(URI url, Void using, Expr.ImportMode mode, byte[] hash) {\n\n    List<String> parts = getUrlPathParts(url);\n\n    for (String part : parts) {\n      this.writer.writeString(part);\n    }\n\n    if (url.getQuery() == null) {\n      this.writer.writeNull();\n    } else {\n      this.writer.writeString(url.getQuery());\n    }\n\n    return null;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/binary/Label.java",
    "content": "package org.dhallj.core.binary;\n\nfinal class Label {\n  public static final int APPLICATION = 0;\n  public static final int LAMBDA = 1;\n  public static final int PI = 2;\n  public static final int OPERATOR_APPLICATION = 3;\n  public static final int LIST = 4;\n  public static final int SOME = 5;\n  public static final int MERGE = 6;\n  public static final int RECORD_TYPE = 7;\n  public static final int RECORD_LITERAL = 8;\n  public static final int FIELD_ACCESS = 9;\n  public static final int PROJECTION = 10;\n  public static final int UNION_TYPE = 11;\n  public static final int IF = 14;\n  public static final int NATURAL = 15;\n  public static final int INTEGER = 16;\n  public static final int TEXT = 18;\n  public static final int ASSERT = 19;\n  public static final int IMPORT = 24;\n  public static final int LET = 25;\n  public static final int ANNOTATED = 26;\n  public static final int TO_MAP = 27;\n  public static final int EMPTY_LIST_WITH_ABSTRACT_TYPE = 28;\n  public static final int WITH = 29;\n\n  public static final int DATE = 30;\n  public static final int TIME = 31;\n  public static final int TIME_ZONE = 32;\n\n  public static final int IMPORT_TYPE_REMOTE_HTTP = 0;\n  public static final int IMPORT_TYPE_REMOTE_HTTPS = 1;\n  public static final int IMPORT_TYPE_LOCAL_ABSOLUTE = 2;\n  public static final int IMPORT_TYPE_LOCAL_HERE = 3;\n  public static final int IMPORT_TYPE_LOCAL_PARENT = 4;\n  public static final int IMPORT_TYPE_LOCAL_HOME = 5;\n  public static final int IMPORT_TYPE_ENV = 6;\n  public static final int IMPORT_TYPE_MISSING = 7;\n  // Allows CBOR tiny field encoding but leaves room for Dhall spec to expand import types\n  public static final int IMPORT_TYPE_CLASSPATH = 23;\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/converters/JsonConverter.java",
    "content": "package org.dhallj.core.converters;\n\nimport java.math.BigInteger;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Visitor;\n\npublic final class JsonConverter extends Visitor.Constant<Boolean> {\n  private final JsonHandler handler;\n  private final boolean escapeStrings;\n\n  public JsonConverter(JsonHandler handler, boolean escapeStrings) {\n    super(false);\n    this.handler = handler;\n    this.escapeStrings = escapeStrings;\n  }\n\n  public JsonConverter(JsonHandler handler) {\n    this(handler, true);\n  }\n\n  public static final String toCompactString(Expr expr) {\n    JsonHandler.CompactStringPrinter handler = new JsonHandler.CompactStringPrinter();\n    boolean isConverted = expr.accept(new JsonConverter(handler));\n    if (isConverted) {\n      return handler.toString();\n    } else {\n      return null;\n    }\n  }\n\n  private static final String escape(String input) {\n    StringBuilder builder = new StringBuilder();\n\n    for (int i = 0; i < input.length(); i++) {\n      char c = input.charAt(i);\n\n      if (c == '\\\\') {\n        char next = input.charAt(++i);\n\n        if (next == '\"') {\n          builder.append(\"\\\\\\\"\");\n        } else if (next == '$') {\n          builder.append(\"$\");\n        } else {\n          builder.append(c);\n          builder.append(next);\n        }\n      } else if (c == '\"') {\n        builder.append(\"\\\\\\\"\");\n      } else {\n        builder.append(c);\n      }\n    }\n\n    return builder.toString();\n  }\n\n  @Override\n  public boolean sortFields() {\n    return false;\n  }\n\n  @Override\n  public boolean flattenToMapLists() {\n    return true;\n  }\n\n  @Override\n  public Boolean onNatural(Expr self, BigInteger value) {\n    this.handler.onNumber(value);\n    return true;\n  }\n\n  @Override\n  public Boolean onInteger(Expr self, BigInteger value) {\n    this.handler.onNumber(value);\n    return true;\n  }\n\n  @Override\n  public Boolean onDouble(Expr self, double value) {\n    this.handler.onDouble(value);\n    return true;\n  }\n\n  @Override\n  public Boolean onBuiltIn(Expr self, String name) {\n    if (name.equals(\"True\")) {\n      this.handler.onBoolean(true);\n      return true;\n    } else if (name.equals(\"False\")) {\n      this.handler.onBoolean(false);\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  @Override\n  public Boolean onText(String[] parts, List<Boolean> interpolated) {\n    if (parts.length == 1) {\n      if (this.escapeStrings) {\n        this.handler.onString(escape(parts[0]));\n      } else {\n        this.handler.onString(parts[0]);\n      }\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  @Override\n  public boolean prepareNonEmptyList(int size) {\n    this.handler.onArrayStart();\n    return true;\n  }\n\n  @Override\n  public boolean prepareNonEmptyListElement(int index) {\n    if (index > 0) {\n      this.handler.onArrayElementGap();\n    }\n    return true;\n  }\n\n  @Override\n  public Boolean onNonEmptyList(List<Boolean> values) {\n    for (boolean value : values) {\n      if (!value) {\n        return false;\n      }\n    }\n    this.handler.onArrayEnd();\n    return true;\n  }\n\n  @Override\n  public Boolean onEmptyList(Boolean type) {\n    this.handler.onArrayStart();\n    this.handler.onArrayEnd();\n    return true;\n  }\n\n  @Override\n  public boolean prepareRecord(int size) {\n    this.handler.onObjectStart();\n    return true;\n  }\n\n  @Override\n  public boolean prepareRecordField(String name, Expr type, int index) {\n    if (index > 0) {\n      this.handler.onObjectFieldGap();\n    }\n    if (this.escapeStrings) {\n      this.handler.onObjectField(escape(name));\n    } else {\n      this.handler.onObjectField(name);\n    }\n    return true;\n  }\n\n  @Override\n  public Boolean onRecord(final List<Entry<String, Boolean>> fields) {\n    for (Entry<String, Boolean> field : fields) {\n      if (!field.getValue()) {\n        return false;\n      }\n    }\n    this.handler.onObjectEnd();\n    return true;\n  }\n\n  @Override\n  public boolean prepareFieldAccess(Expr base, String fieldName) {\n    List<Entry<String, Expr>> asUnion = Expr.Util.asUnionType(base);\n\n    if (asUnion != null) {\n      for (Entry<String, Expr> field : asUnion) {\n        if (field.getKey().equals(fieldName) && field.getValue() == null) {\n          this.handler.onString(escape(fieldName));\n          return false;\n        }\n      }\n    }\n    return true;\n  }\n\n  @Override\n  public Boolean onFieldAccess(Boolean base, String fieldName) {\n    return base == null || base;\n  }\n\n  @Override\n  public boolean prepareApplication(Expr base, int size) {\n    String asBuiltIn = Expr.Util.asBuiltIn(base);\n\n    if (asBuiltIn != null && size == 1) {\n      if (asBuiltIn.equals(\"Some\")) {\n        return false;\n      } else if (asBuiltIn.equals(\"None\")) {\n        this.handler.onNull();\n        return false;\n      }\n    } else {\n      Entry<Expr, String> asFieldAccess = Expr.Util.asFieldAccess(base);\n\n      if (asFieldAccess != null) {\n        List<Entry<String, Expr>> asUnion = Expr.Util.asUnionType(asFieldAccess.getKey());\n\n        if (asUnion != null) {\n          for (Entry<String, Expr> field : asUnion) {\n            if (field.getKey().equals(asFieldAccess.getValue()) && field.getValue() != null) {\n              return false;\n            }\n          }\n        }\n      }\n    }\n\n    return true;\n  }\n\n  @Override\n  public Boolean onApplication(Boolean base, List<Boolean> args) {\n    return base == null || base;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/converters/JsonHandler.java",
    "content": "package org.dhallj.core.converters;\n\nimport java.io.PrintWriter;\nimport java.math.BigInteger;\n\npublic interface JsonHandler {\n  void onNull();\n\n  void onBoolean(boolean value);\n\n  void onNumber(BigInteger value);\n\n  void onDouble(double value);\n\n  void onString(String value);\n\n  void onArrayStart();\n\n  void onArrayEnd();\n\n  void onArrayElementGap();\n\n  void onObjectStart();\n\n  void onObjectEnd();\n\n  void onObjectField(String name);\n\n  void onObjectFieldGap();\n\n  public static final class CompactPrinter implements JsonHandler {\n    private final PrintWriter writer;\n\n    public CompactPrinter(PrintWriter writer) {\n      this.writer = writer;\n    }\n\n    public void onNull() {\n      this.writer.print(\"null\");\n    }\n\n    public void onBoolean(boolean value) {\n      this.writer.print(value);\n    }\n\n    public void onNumber(BigInteger value) {\n      this.writer.print(value.toString());\n    }\n\n    public void onDouble(double value) {\n      this.writer.print(value);\n    }\n\n    public void onString(String value) {\n      this.writer.printf(\"\\\"%s\\\"\", value);\n    }\n\n    public void onArrayStart() {\n      this.writer.print(\"[\");\n    }\n\n    public void onArrayEnd() {\n      this.writer.print(\"]\");\n    }\n\n    public void onArrayElementGap() {\n      this.writer.print(\",\");\n    }\n\n    public void onObjectStart() {\n      this.writer.print(\"{\");\n    }\n\n    public void onObjectEnd() {\n      this.writer.print(\"}\");\n    }\n\n    public void onObjectField(String name) {\n      this.writer.printf(\"\\\"%s\\\":\", name);\n    }\n\n    public void onObjectFieldGap() {\n      this.writer.print(\",\");\n    }\n  }\n\n  public static final class CompactStringPrinter implements JsonHandler {\n    private final StringBuilder builder;\n\n    public CompactStringPrinter() {\n      this.builder = new StringBuilder();\n    }\n\n    public String toString() {\n      return this.builder.toString();\n    }\n\n    public void onNull() {\n      this.builder.append(\"null\");\n    }\n\n    public void onBoolean(boolean value) {\n      this.builder.append(value);\n    }\n\n    public void onNumber(BigInteger value) {\n      this.builder.append(value.toString());\n    }\n\n    public void onDouble(double value) {\n      this.builder.append(value);\n    }\n\n    public void onString(String value) {\n      this.builder.append(String.format(\"\\\"%s\\\"\", value));\n    }\n\n    public void onArrayStart() {\n      this.builder.append(\"[\");\n    }\n\n    public void onArrayEnd() {\n      this.builder.append(\"]\");\n    }\n\n    public void onArrayElementGap() {\n      this.builder.append(\",\");\n    }\n\n    public void onObjectStart() {\n      this.builder.append(\"{\");\n    }\n\n    public void onObjectEnd() {\n      this.builder.append(\"}\");\n    }\n\n    public void onObjectField(String name) {\n      this.builder.append(String.format(\"\\\"%s\\\":\", name));\n    }\n\n    public void onObjectFieldGap() {\n      this.builder.append(\",\");\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/AlphaNormalize.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Visitor;\n\n/**\n * Performs alpha normalization.\n *\n * <p>Morally this is equivalent to the following (on non-underscore bindings):\n *\n * <pre>\n * input.increment(\"_\").substitute(name, 0, Expr.Constants.UNDERSCORE).decrement(name);\n * </pre>\n *\n * The implementation here is necessary to fit the visitor API.\n *\n * <p>Note that this visitor maintains internal state and instances should not be reused.\n */\npublic final class AlphaNormalize extends Visitor.Identity {\n  // We interpret any underscores as implicitly having this index added to their own.\n  private int newUnderscoreDepth = 0;\n\n  // The total number of underscores.\n  private int underscoreDepth = 0;\n\n  // We change any other name to an underscore whose index we compute from the depth we track here.\n  private final Map<String, LinkedList<Integer>> nameDepths =\n      new HashMap<String, LinkedList<Integer>>();\n\n  @Override\n  public Expr onIdentifier(Expr self, String name, long index) {\n    if (name.equals(\"_\")) {\n      return Expr.makeIdentifier(name, index + this.newUnderscoreDepth);\n    } else {\n      LinkedList<Integer> depths = this.nameDepths.get(name);\n\n      if (depths == null) {\n        return self;\n      } else if (index < depths.size()) {\n        return Expr.makeIdentifier(\"_\", underscoreDepth - depths.get((int) index));\n      } else {\n        return Expr.makeIdentifier(name, index - depths.size());\n      }\n    }\n  }\n\n  @Override\n  public void bind(String name, Expr type) {\n    this.underscoreDepth += 1;\n    if (!name.equals(\"_\")) {\n      this.newUnderscoreDepth += 1;\n\n      LinkedList<Integer> nameDepth = this.nameDepths.get(name);\n      if (nameDepth == null) {\n        nameDepth = new LinkedList<Integer>();\n        nameDepths.put(name, nameDepth);\n      }\n      nameDepth.push(this.underscoreDepth);\n    }\n  }\n\n  @Override\n  public Expr onLambda(String name, Expr type, Expr result) {\n    this.underscoreDepth -= 1;\n    if (!name.equals(\"_\")) {\n      this.newUnderscoreDepth -= 1;\n      this.nameDepths.get(name).pop();\n    }\n    return Expr.makeLambda(\"_\", type, result);\n  }\n\n  @Override\n  public Expr onPi(String name, Expr type, Expr result) {\n    this.underscoreDepth -= 1;\n    if (!name.equals(\"_\")) {\n      this.newUnderscoreDepth -= 1;\n      this.nameDepths.get(name).pop();\n    }\n    return Expr.makePi(\"_\", type, result);\n  }\n\n  @Override\n  public Expr onLet(List<Expr.LetBinding<Expr>> bindings, Expr body) {\n    List<Expr.LetBinding<Expr>> newBindings = new ArrayList<>(bindings.size());\n\n    for (Expr.LetBinding<Expr> binding : bindings) {\n      String name = binding.getName();\n\n      this.underscoreDepth -= 1;\n      if (!name.equals(\"_\")) {\n        this.newUnderscoreDepth -= 1;\n        this.nameDepths.get(name).pop();\n      }\n\n      newBindings.add(new Expr.LetBinding<>(\"_\", binding.getType(), binding.getValue()));\n    }\n\n    return Expr.makeLet(newBindings, body);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalize.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Source;\nimport org.dhallj.core.Visitor;\n\n/**\n * Performs beta normalization.\n *\n * <p>This is a stateless visitor intended for use as a singleton.\n */\npublic final class BetaNormalize extends Visitor.NoPrepareEvents<Expr> {\n  public static final Visitor<Expr> instance = new BetaNormalize();\n\n  public void bind(String name, Expr type) {}\n\n  public Expr onNote(Expr base, Source source) {\n    return base;\n  }\n\n  public Expr onNatural(Expr self, BigInteger value) {\n    return self;\n  }\n\n  public Expr onInteger(Expr self, BigInteger value) {\n    return self;\n  }\n\n  public Expr onDouble(Expr self, double value) {\n    return self;\n  }\n\n  public Expr onDate(Expr self, int year, int month, int day) {\n    return self;\n  }\n\n  public Expr onTime(Expr self, int hour, int minute, int second, BigDecimal fractional) {\n    return self;\n  }\n\n  public Expr onTimeZone(Expr self, int minutes) {\n    return self;\n  }\n\n  public Expr onBuiltIn(Expr self, String name) {\n    return self;\n  }\n\n  public Expr onIdentifier(Expr self, String name, long index) {\n    return self;\n  }\n\n  public Expr onLambda(String name, Expr type, Expr result) {\n    return Expr.makeLambda(name, type, result);\n  }\n\n  public Expr onPi(String name, Expr type, Expr result) {\n    return Expr.makePi(name, type, result);\n  }\n\n  public Expr onLet(List<Expr.LetBinding<Expr>> bindings, Expr body) {\n    Expr result = body;\n\n    for (int i = bindings.size() - 1; i >= 0; i--) {\n      Expr.LetBinding<Expr> binding = bindings.get(i);\n      String name = binding.getName();\n\n      result = result.substitute(name, binding.getValue());\n    }\n\n    return result.accept(this);\n  }\n\n  public Expr onText(String[] parts, List<Expr> interpolated) {\n    return BetaNormalizeTextLiteral.apply(parts, interpolated);\n  }\n\n  public Expr onNonEmptyList(List<Expr> values) {\n    return Expr.makeNonEmptyListLiteral(values);\n  }\n\n  public Expr onEmptyList(Expr type) {\n    return Expr.makeEmptyListLiteral(type);\n  }\n\n  public Expr onRecord(List<Entry<String, Expr>> fields) {\n    Collections.sort(fields, NormalizationUtilities.entryComparator);\n    return Expr.makeRecordLiteral(fields);\n  }\n\n  public Expr onRecordType(List<Entry<String, Expr>> fields) {\n    Collections.sort(fields, NormalizationUtilities.entryComparator);\n    return Expr.makeRecordType(fields);\n  }\n\n  public Expr onUnionType(List<Entry<String, Expr>> fields) {\n    Collections.sort(fields, NormalizationUtilities.entryComparator);\n    return Expr.makeUnionType(fields);\n  }\n\n  public Expr onFieldAccess(Expr base, String fieldName) {\n    return BetaNormalizeFieldAccess.apply(base, fieldName);\n  }\n\n  public Expr onProjection(Expr base, String[] fieldNames) {\n    return BetaNormalizeProjection.apply(base, fieldNames);\n  }\n\n  public Expr onProjectionByType(Expr base, Expr arg) {\n    List<Entry<String, Expr>> argAsRecordType = Expr.Util.asRecordType(arg);\n    Set<String> keys = new TreeSet<>();\n    for (Entry<String, Expr> entry : argAsRecordType) {\n      keys.add(entry.getKey());\n    }\n\n    return Expr.makeProjection(base, keys.toArray(new String[keys.size()])).accept(this);\n  }\n\n  public Expr onApplication(Expr base, List<Expr> args) {\n    return BetaNormalizeApplication.apply(base, args);\n  }\n\n  public Expr onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    return BetaNormalizeOperatorApplication.apply(operator, lhs, rhs);\n  }\n\n  public Expr onIf(Expr predicate, Expr thenValue, Expr elseValue) {\n    return BetaNormalizeIf.apply(predicate, thenValue, elseValue);\n  }\n\n  public Expr onAnnotated(Expr base, Expr type) {\n    return base;\n  }\n\n  public Expr onAssert(Expr type) {\n    return Expr.makeAssert(type);\n  }\n\n  public Expr onMerge(Expr handlers, Expr union, Expr type) {\n    return BetaNormalizeMerge.apply(handlers, union, type);\n  }\n\n  public Expr onToMap(Expr base, Expr type) {\n    return BetaNormalizeToMap.apply(base, type);\n  }\n\n  public Expr onWith(Expr base, String[] path, Expr value) {\n    return BetaNormalizeWith.apply(base, path, value);\n  }\n\n  public Expr onMissingImport(Expr.ImportMode mode, byte[] hash) {\n    return Expr.makeMissingImport(mode, hash);\n  }\n\n  public Expr onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n    return Expr.makeEnvImport(value, mode, hash);\n  }\n\n  public Expr onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    return Expr.makeLocalImport(path, mode, hash);\n  }\n\n  @Override\n  public Expr onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    return Expr.makeClasspathImport(path, mode, hash);\n  }\n\n  public Expr onRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n    return Expr.makeRemoteImport(url, using, mode, hash);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeApplication.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.math.BigInteger;\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\n\nfinal class BetaNormalizeApplication {\n  private static Expr applyLambdas(Expr base, final List<Expr> args) {\n    Expr currentLambda = null;\n    Expr current = base;\n    int i = 0;\n\n    while (current != null && i < args.size()) {\n      current = Expr.Util.applyAsLambda(current, args.get(i));\n      if (current == null) {\n        break;\n      } else {\n        currentLambda = current.accept(BetaNormalize.instance);\n        i += 1;\n      }\n    }\n\n    if (currentLambda != null) {\n      for (int j = i; j < args.size(); j++) {\n        currentLambda = Expr.makeApplication(currentLambda, args.get(j));\n      }\n      currentLambda = currentLambda.accept(BetaNormalize.instance);\n    }\n\n    return currentLambda;\n  }\n\n  private static final Expr booleanToExpr(boolean value) {\n    return value ? Expr.Constants.TRUE : Expr.Constants.FALSE;\n  }\n\n  static final Expr apply(Expr base, List<Expr> args) {\n    String builtIn = Expr.Util.asBuiltIn(base);\n\n    if (builtIn != null) {\n      if (builtIn.equals(\"Natural/fold\") && args.size() >= 4) {\n        Expr result = naturalFold(args);\n\n        if (result != null) {\n          return result;\n        }\n      } else if (builtIn.equals(\"List/fold\") && args.size() >= 5) {\n        Expr result = listFold(args);\n\n        if (result != null) {\n          return result;\n        }\n      } else if (builtIn.equals(\"Text/replace\") && args.size() >= 3) {\n        Expr result = textReplace(args);\n\n        if (result != null) {\n          return result;\n        }\n      } else if (args.size() == 1) {\n        Expr result = arity1(builtIn, args.get(0));\n\n        if (result != null) {\n          return result;\n        }\n      } else if (args.size() == 2) {\n        Expr result = arity2(builtIn, args.get(0), args.get(1));\n\n        if (result != null) {\n          return result;\n        }\n      }\n    } else {\n      Expr result = applyLambdas(base, args);\n\n      if (result != null) {\n        return result;\n      }\n    }\n\n    return Expr.makeApplication(base, args);\n  }\n\n  private static final Entry<String, Expr> indexField =\n      new SimpleImmutableEntry<>(\"index\", Expr.Constants.NATURAL);\n\n  private static final Expr indexedRecordType(Expr type) {\n    Entry[] fields = {indexField, new SimpleImmutableEntry<>(\"value\", type)};\n    return Expr.makeRecordType(fields);\n  }\n\n  private static final BigInteger TWO = new BigInteger(\"2\");\n\n  private static final boolean isBigIntegerEven(BigInteger value) {\n    return value.mod(TWO).equals(BigInteger.ZERO);\n  }\n\n  private static final boolean isBigIntegerNatural(BigInteger value) {\n    return value.compareTo(BigInteger.ZERO) >= 0;\n  }\n\n  private static final Expr arity1(String identifier, Expr arg) {\n    if (identifier.equals(\"Natural/isZero\")) {\n      BigInteger argAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg);\n\n      if (argAsNaturalLiteral != null) {\n        return booleanToExpr(argAsNaturalLiteral.equals(BigInteger.ZERO));\n      }\n    } else if (identifier.equals(\"Natural/even\")) {\n      BigInteger argAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg);\n\n      if (argAsNaturalLiteral != null) {\n        return booleanToExpr(isBigIntegerEven(argAsNaturalLiteral));\n      }\n    } else if (identifier.equals(\"Natural/odd\")) {\n      BigInteger argAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg);\n\n      if (argAsNaturalLiteral != null) {\n        return booleanToExpr(!isBigIntegerEven(argAsNaturalLiteral));\n      }\n    } else if (identifier.equals(\"Natural/toInteger\")) {\n      BigInteger argAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg);\n\n      if (argAsNaturalLiteral != null) {\n        return Expr.makeIntegerLiteral(argAsNaturalLiteral);\n      }\n    } else if (identifier.equals(\"Natural/show\")) {\n      BigInteger argAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg);\n\n      if (argAsNaturalLiteral != null) {\n        return Expr.makeTextLiteral(argAsNaturalLiteral.toString());\n      }\n    } else if (identifier.equals(\"Integer/negate\")) {\n      BigInteger argAsIntegerLiteral = Expr.Util.asIntegerLiteral(arg);\n\n      if (argAsIntegerLiteral != null) {\n        return Expr.makeIntegerLiteral(argAsIntegerLiteral.negate());\n      }\n    } else if (identifier.equals(\"Integer/clamp\")) {\n      BigInteger argAsIntegerLiteral = Expr.Util.asIntegerLiteral(arg);\n\n      if (argAsIntegerLiteral != null) {\n        if (isBigIntegerNatural(argAsIntegerLiteral)) {\n          return Expr.makeNaturalLiteral(argAsIntegerLiteral);\n        } else {\n          return Expr.makeNaturalLiteral(BigInteger.ZERO);\n        }\n      }\n    } else if (identifier.equals(\"Integer/toDouble\")) {\n      BigInteger argAsIntegerLiteral = Expr.Util.asIntegerLiteral(arg);\n\n      if (argAsIntegerLiteral != null) {\n        return Expr.makeDoubleLiteral(argAsIntegerLiteral.doubleValue());\n      }\n    } else if (identifier.equals(\"Integer/show\")) {\n      BigInteger argAsIntegerLiteral = Expr.Util.asIntegerLiteral(arg);\n\n      if (argAsIntegerLiteral != null) {\n        String sign = isBigIntegerNatural(argAsIntegerLiteral) ? \"+\" : \"\";\n        return Expr.makeTextLiteral(sign + argAsIntegerLiteral.toString());\n      }\n    } else if (identifier.equals(\"Double/show\")) {\n      Double argAsDoubleLiteral = Expr.Util.asDoubleLiteral(arg);\n\n      if (argAsDoubleLiteral != null) {\n        return Expr.makeTextLiteral(argAsDoubleLiteral.toString());\n      }\n    } else if (identifier.equals(\"Text/show\")) {\n      String argAsSimpleTextLiteral = Expr.Util.asSimpleTextLiteral(arg);\n\n      if (argAsSimpleTextLiteral != null) {\n        return Expr.makeTextLiteral(Expr.Util.escapeText(argAsSimpleTextLiteral, true));\n      }\n    } else if (identifier.equals(\"Natural/build\")) {\n      return Expr.makeApplication(\n              Expr.makeApplication(\n                  Expr.makeApplication(arg, Expr.Constants.NATURAL),\n                  Expr.makeLambda(\n                      \"x\",\n                      Expr.Constants.NATURAL,\n                      Expr.makeOperatorApplication(\n                          Operator.PLUS,\n                          Expr.makeIdentifier(\"x\"),\n                          Expr.makeNaturalLiteral(BigInteger.ONE)))),\n              Expr.makeNaturalLiteral(BigInteger.ZERO))\n          .accept(BetaNormalize.instance);\n    }\n    // None matched, so we can't simplify.\n    return null;\n  }\n\n  private static final Expr[] prependValue = new Expr[] {Expr.makeIdentifier(\"a\")};\n  private static final Expr prependExpr =\n      Expr.makeOperatorApplication(\n          Operator.LIST_APPEND,\n          Expr.makeNonEmptyListLiteral(prependValue),\n          Expr.makeIdentifier(\"as\"));\n\n  private static final Expr arity2(String identifier, Expr arg1, Expr arg2) {\n\n    if (identifier.equals(\"List/build\")) {\n      Expr listA = Expr.makeApplication(Expr.Constants.LIST, arg1);\n\n      return Expr.makeApplication(\n              Expr.makeApplication(\n                  Expr.makeApplication(arg2, listA),\n                  Expr.makeLambda(\n                      \"a\",\n                      arg1,\n                      Expr.makeLambda(\n                          \"as\",\n                          Expr.makeApplication(Expr.Constants.LIST, arg1.increment(\"a\")),\n                          prependExpr))),\n              Expr.makeEmptyListLiteral(listA))\n          .accept(BetaNormalize.instance);\n    } else if (identifier.equals(\"Natural/subtract\")) {\n      BigInteger firstAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg1);\n      BigInteger secondAsNaturalLiteral = Expr.Util.asNaturalLiteral(arg2);\n\n      if (firstAsNaturalLiteral != null) {\n        if (secondAsNaturalLiteral != null) {\n          if (firstAsNaturalLiteral.compareTo(secondAsNaturalLiteral) < 0) {\n            return Expr.makeNaturalLiteral(secondAsNaturalLiteral.subtract(firstAsNaturalLiteral));\n          } else {\n            return Expr.Constants.ZERO;\n          }\n        } else {\n          if (firstAsNaturalLiteral.equals(BigInteger.ZERO)) {\n            return arg2;\n          }\n        }\n      } else {\n        if (secondAsNaturalLiteral != null && secondAsNaturalLiteral.equals(BigInteger.ZERO)) {\n          return Expr.Constants.ZERO;\n        }\n      }\n\n      if (arg1.equivalent(arg2)) {\n        return Expr.Constants.ZERO;\n      }\n    } else if (identifier.equals(\"List/length\")) {\n      List<Expr> argAsListLiteral = Expr.Util.asListLiteral(arg2);\n\n      if (argAsListLiteral != null) {\n        return Expr.makeNaturalLiteral(BigInteger.valueOf(argAsListLiteral.size()));\n      }\n    } else if (identifier.equals(\"List/reverse\")) {\n      List<Expr> argAsListLiteral = Expr.Util.asListLiteral(arg2);\n\n      if (argAsListLiteral != null) {\n        List<Expr> result = new ArrayList<>(argAsListLiteral);\n        Collections.reverse(result);\n        if (result.isEmpty()) {\n          return arg2;\n        } else {\n          return Expr.makeNonEmptyListLiteral(result);\n        }\n      }\n    } else if (identifier.equals(\"List/head\")) {\n      List<Expr> argAsListLiteral = Expr.Util.asListLiteral(arg2);\n\n      if (argAsListLiteral != null) {\n        if (argAsListLiteral.isEmpty()) {\n          return Expr.makeApplication(Expr.Constants.NONE, arg1);\n        } else {\n          return Expr.makeApplication(Expr.Constants.SOME, argAsListLiteral.get(0));\n        }\n      }\n    } else if (identifier.equals(\"List/last\")) {\n      List<Expr> argAsListLiteral = Expr.Util.asListLiteral(arg2);\n\n      if (argAsListLiteral != null) {\n        if (argAsListLiteral.isEmpty()) {\n          return Expr.makeApplication(Expr.Constants.NONE, arg1);\n        } else {\n          return Expr.makeApplication(\n              Expr.Constants.SOME, argAsListLiteral.get(argAsListLiteral.size() - 1));\n        }\n      }\n    } else if (identifier.equals(\"List/indexed\")) {\n      List<Expr> argAsListLiteral = Expr.Util.asListLiteral(arg2);\n\n      if (argAsListLiteral != null) {\n        List<Expr> result = new ArrayList<>(argAsListLiteral.size());\n        int i = 0;\n\n        for (Expr value : argAsListLiteral) {\n          List<Entry<String, Expr>> fields = new ArrayList<>();\n          fields.add(\n              new SimpleImmutableEntry<>(\n                  \"index\", Expr.makeNaturalLiteral(BigInteger.valueOf(i++))));\n          fields.add(new SimpleImmutableEntry<>(\"value\", value));\n          result.add(Expr.makeRecordLiteral(fields));\n        }\n\n        if (result.isEmpty()) {\n          return Expr.makeEmptyListLiteral(\n              Expr.makeApplication(Expr.Constants.LIST, indexedRecordType(arg1)));\n        } else {\n          return Expr.makeNonEmptyListLiteral(result);\n        }\n      }\n    }\n    // None matched, so we can't simplify.\n    return null;\n  }\n\n  private static List<Expr> drop(List<Expr> args, int count) {\n    List<Expr> result = new ArrayList<Expr>(args.size() - count);\n    for (int i = count; i < args.size(); i++) {\n      result.add(args.get(i));\n    }\n    return result;\n  }\n\n  private static final Expr naturalFold(List<Expr> args) {\n    BigInteger firstAsNaturalLiteral = Expr.Util.asNaturalLiteral(args.get(0));\n\n    if (firstAsNaturalLiteral != null) {\n      Expr applied = null;\n      if (firstAsNaturalLiteral.equals(BigInteger.ZERO)) {\n        applied = args.get(3);\n      } else {\n        applied =\n            Expr.makeApplication(\n                    args.get(2),\n                    Expr.makeApplication(\n                        Expr.makeApplication(\n                            Expr.makeApplication(\n                                Expr.makeApplication(\n                                    Expr.Constants.NATURAL_FOLD,\n                                    Expr.makeNaturalLiteral(\n                                        firstAsNaturalLiteral.subtract(BigInteger.ONE))),\n                                args.get(1)),\n                            args.get(2)),\n                        args.get(3)))\n                .accept(BetaNormalize.instance);\n      }\n\n      if (applied == null) {\n        return null;\n      }\n\n      if (args.size() == 4) {\n        return applied;\n      } else {\n        return Expr.makeApplication(applied, drop(args, 4)).accept(BetaNormalize.instance);\n      }\n    }\n    return null;\n  }\n\n  private static final Expr listFold(List<Expr> args) {\n    List<Expr> listArg = Expr.Util.asListLiteral(args.get(1));\n\n    if (listArg != null) {\n      Expr applied = null;\n      if (!listArg.isEmpty()) {\n        Expr head = listArg.get(0);\n\n        Expr tail;\n        if (listArg.size() == 1) {\n          tail = Expr.makeEmptyListLiteral(Expr.makeApplication(Expr.Constants.LIST, args.get(0)));\n        } else {\n          List<Expr> listArgTail = new ArrayList<>(listArg);\n          listArgTail.remove(0);\n\n          tail = Expr.makeNonEmptyListLiteral(listArgTail);\n        }\n        applied =\n            Expr.makeApplication(\n                    Expr.makeApplication(args.get(3), head),\n                    Expr.makeApplication(\n                        Expr.makeApplication(\n                            Expr.makeApplication(\n                                Expr.makeApplication(\n                                    Expr.makeApplication(Expr.Constants.LIST_FOLD, args.get(0)),\n                                    tail),\n                                args.get(2)),\n                            args.get(3)),\n                        args.get(4)))\n                .accept(BetaNormalize.instance);\n      } else {\n        applied = args.get(4);\n      }\n\n      if (args.size() == 5) {\n        return applied;\n      } else {\n        return Expr.makeApplication(applied, drop(args, 5)).accept(BetaNormalize.instance);\n      }\n    }\n    return null;\n  }\n\n  private static final Expr textReplace(List<Expr> args) {\n    String needle = Expr.Util.asSimpleTextLiteral(args.get(0));\n\n    if (needle != null) {\n      if (needle.length() == 0) {\n        return args.get(2);\n      } else {\n        String haystack = Expr.Util.asSimpleTextLiteral(args.get(2));\n\n        if (haystack != null) {\n          String pattern = java.util.regex.Pattern.quote(needle);\n          String[] parts = haystack.split(pattern, -1);\n\n          Expr[] interpolated = new Expr[parts.length - 1];\n          Expr replacement = args.get(1);\n\n          for (int i = 0; i < parts.length - 1; i += 1) {\n            interpolated[i] = replacement;\n          }\n\n          return Expr.makeTextLiteral(parts, interpolated).accept(BetaNormalize.instance);\n        }\n      }\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeFieldAccess.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.ExternalVisitor;\nimport org.dhallj.core.Operator;\n\nfinal class BetaNormalizeFieldAccess extends ExternalVisitor.Constant<Expr> {\n  private final String fieldName;\n\n  public BetaNormalizeFieldAccess(String fieldName) {\n    super(null);\n    this.fieldName = fieldName;\n  }\n\n  static final Expr apply(Expr base, String fieldName) {\n    Expr result = base.accept(new BetaNormalizeFieldAccess(fieldName));\n\n    if (result != null) {\n      return result;\n    } else {\n      return Expr.makeFieldAccess(base, fieldName);\n    }\n  }\n\n  @Override\n  public Expr onRecord(Iterable<Entry<String, Expr>> fields, int size) {\n    return NormalizationUtilities.lookup(fields, fieldName);\n  }\n\n  @Override\n  public Expr onProjection(Expr base, String[] fieldNames0) {\n    return Expr.makeFieldAccess(base, fieldName).accept(BetaNormalize.instance);\n  }\n\n  @Override\n  public Expr onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    if (operator.equals(Operator.PREFER)) {\n      List<Entry<String, Expr>> lhsFields = Expr.Util.asRecordLiteral(lhs);\n      if (lhsFields != null) {\n        Entry<String, Expr> lhsFound = NormalizationUtilities.lookupEntry(lhsFields, fieldName);\n\n        if (lhsFound != null) {\n          List<Entry<String, Expr>> singleton = new ArrayList();\n          singleton.add(lhsFound);\n\n          return Expr.makeFieldAccess(\n              Expr.makeOperatorApplication(Operator.PREFER, Expr.makeRecordLiteral(singleton), rhs),\n              fieldName);\n        } else {\n          return Expr.makeFieldAccess(rhs, fieldName);\n        }\n      } else {\n        List<Entry<String, Expr>> rhsFields = Expr.Util.asRecordLiteral(rhs);\n        if (rhsFields != null) {\n          Expr rhsFound = NormalizationUtilities.lookup(rhsFields, fieldName);\n\n          if (rhsFound != null) {\n            return rhsFound;\n          } else {\n            return Expr.makeFieldAccess(lhs, fieldName).accept(BetaNormalize.instance);\n          }\n        }\n      }\n    } else if (operator.equals(Operator.COMBINE)) {\n      List<Entry<String, Expr>> lhsFields = Expr.Util.asRecordLiteral(lhs);\n      if (lhsFields != null) {\n        Entry<String, Expr> lhsFound = NormalizationUtilities.lookupEntry(lhsFields, fieldName);\n\n        if (lhsFound != null) {\n          List<Entry<String, Expr>> singleton = new ArrayList<>();\n          singleton.add(lhsFound);\n\n          return Expr.makeFieldAccess(\n              Expr.makeOperatorApplication(\n                  Operator.COMBINE, Expr.makeRecordLiteral(singleton), rhs),\n              fieldName);\n        } else {\n          return Expr.makeFieldAccess(rhs, fieldName);\n        }\n      } else {\n        List<Entry<String, Expr>> rhsFields = Expr.Util.asRecordLiteral(rhs);\n        if (rhsFields != null) {\n          Entry<String, Expr> rhsFound = NormalizationUtilities.lookupEntry(rhsFields, fieldName);\n\n          if (rhsFound != null) {\n            List<Entry<String, Expr>> singleton = new ArrayList<>();\n            singleton.add(rhsFound);\n\n            return Expr.makeFieldAccess(\n                Expr.makeOperatorApplication(\n                    Operator.COMBINE, lhs, Expr.makeRecordLiteral(singleton)),\n                fieldName);\n          } else {\n            return Expr.makeFieldAccess(lhs, fieldName).accept(BetaNormalize.instance);\n          }\n        }\n      }\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeIf.java",
    "content": "package org.dhallj.core.normalization;\n\nimport org.dhallj.core.Expr;\n\nfinal class BetaNormalizeIf {\n  static final Expr apply(Expr predicate, Expr thenValue, Expr elseValue) {\n    Boolean predicateAsBool = Expr.Util.asBoolLiteral(predicate);\n\n    if (predicateAsBool != null) {\n      return (predicateAsBool) ? thenValue : elseValue;\n    } else {\n      Boolean thenAsBool = Expr.Util.asBoolLiteral(thenValue);\n      Boolean elseAsBool = Expr.Util.asBoolLiteral(elseValue);\n\n      if (thenAsBool != null && elseAsBool != null && thenAsBool && !elseAsBool) {\n        return predicate;\n      } else if (thenValue.equivalent(elseValue)) {\n        return thenValue;\n      } else {\n        return Expr.makeIf(predicate, thenValue, elseValue);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeMerge.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.ExternalVisitor;\nimport org.dhallj.core.Operator;\n\nfinal class BetaNormalizeMerge extends ExternalVisitor.Constant<Expr> {\n  private final List<Entry<String, Expr>> handlers;\n\n  private BetaNormalizeMerge(List<Entry<String, Expr>> handlers) {\n    super(null);\n    this.handlers = handlers;\n  }\n\n  static final Expr apply(Expr handlers, Expr union, Expr type) {\n    List<Entry<String, Expr>> fields = Expr.Util.asRecordLiteral(handlers);\n\n    Expr result = union.accept(new BetaNormalizeMerge(fields));\n\n    if (result != null) {\n      return result.accept(BetaNormalize.instance);\n    } else {\n\n      return Expr.makeMerge(handlers, union, type);\n    }\n  }\n\n  @Override\n  public Expr onFieldAccess(Expr base, String fieldName) {\n    List<Entry<String, Expr>> baseAsUnion = Expr.Util.asUnionType(base);\n\n    if (baseAsUnion != null) {\n      return merge(this.handlers, fieldName);\n    } else {\n      return null;\n    }\n  }\n\n  @Override\n  public Expr onApplication(Expr base, Expr arg) {\n    Entry<Expr, String> baseAsFieldAccess = Expr.Util.asFieldAccess(base);\n    if (baseAsFieldAccess != null) {\n      List<Entry<String, Expr>> accessedAsUnion = Expr.Util.asUnionType(baseAsFieldAccess.getKey());\n\n      if (accessedAsUnion != null) {\n        return merge(this.handlers, baseAsFieldAccess.getValue(), arg);\n      } else {\n        return null;\n      }\n\n    } else {\n      String baseAsBuiltIn = Expr.Util.asBuiltIn(base);\n\n      if (baseAsBuiltIn != null) {\n        if (baseAsBuiltIn.equals(\"Some\")) {\n          return merge(this.handlers, baseAsBuiltIn, arg);\n        } else if (baseAsBuiltIn.equals(\"None\")) {\n          return merge(this.handlers, baseAsBuiltIn);\n        }\n      }\n      return null;\n    }\n  }\n\n  private static Expr merge(List<Entry<String, Expr>> handlers, String fieldName) {\n    return NormalizationUtilities.lookup(handlers, fieldName);\n  }\n\n  private static Expr merge(List<Entry<String, Expr>> handlers, String fieldName, Expr arg) {\n    Expr handler = NormalizationUtilities.lookup(handlers, fieldName);\n    if (handler != null) {\n      return Expr.makeApplication(handler, arg);\n    } else {\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeOperatorApplication.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.TreeMap;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\n\nfinal class BetaNormalizeOperatorApplication {\n  static final Expr apply(Operator operator, Expr lhs, Expr rhs) {\n    if (operator.isBoolOperator()) {\n      Boolean lhsAsBool = Expr.Util.asBoolLiteral(lhs);\n      Boolean rhsAsBool = Expr.Util.asBoolLiteral(rhs);\n\n      if (operator.equals(Operator.OR)) {\n        if (lhsAsBool != null) {\n          return lhsAsBool ? lhs : rhs;\n        } else if (rhsAsBool != null) {\n          return rhsAsBool ? rhs : lhs;\n        } else if (lhs.equivalent(rhs)) {\n          return lhs;\n        }\n      } else if (operator.equals(Operator.AND)) {\n        if (lhsAsBool != null) {\n          return lhsAsBool ? rhs : lhs;\n        } else if (rhsAsBool != null) {\n          return rhsAsBool ? lhs : rhs;\n        } else if (lhs.equivalent(rhs)) {\n          return lhs;\n        }\n      } else if (operator.equals(Operator.EQUALS)) {\n        if (lhsAsBool != null && lhsAsBool) {\n          return rhs;\n        } else if (rhsAsBool != null && rhsAsBool) {\n          return lhs;\n        } else if (lhs.equivalent(rhs)) {\n          return Expr.Constants.TRUE;\n        }\n      } else if (operator.equals(Operator.NOT_EQUALS)) {\n        if (lhsAsBool != null && !lhsAsBool) {\n          return rhs;\n        } else if (rhsAsBool != null && !rhsAsBool) {\n          return lhs;\n        } else if (lhs.equivalent(rhs)) {\n          return Expr.Constants.FALSE;\n        }\n      }\n    } else if (operator.equals(Operator.PLUS)) {\n      BigInteger lhsAsNaturalLiteral = Expr.Util.asNaturalLiteral(lhs);\n      BigInteger rhsAsNaturalLiteral = Expr.Util.asNaturalLiteral(rhs);\n\n      if (lhsAsNaturalLiteral != null) {\n        if (rhsAsNaturalLiteral != null) {\n          return Expr.makeNaturalLiteral(lhsAsNaturalLiteral.add(rhsAsNaturalLiteral));\n        } else if (lhsAsNaturalLiteral.equals(BigInteger.ZERO)) {\n          return rhs;\n        }\n      } else if (rhsAsNaturalLiteral != null && rhsAsNaturalLiteral.equals(BigInteger.ZERO)) {\n        return lhs;\n      }\n    } else if (operator.equals(Operator.TIMES)) {\n      BigInteger lhsAsNaturalLiteral = Expr.Util.asNaturalLiteral(lhs);\n      BigInteger rhsAsNaturalLiteral = Expr.Util.asNaturalLiteral(rhs);\n\n      if (lhsAsNaturalLiteral != null) {\n        if (rhsAsNaturalLiteral != null) {\n          return Expr.makeNaturalLiteral(lhsAsNaturalLiteral.multiply(rhsAsNaturalLiteral));\n        } else if (lhsAsNaturalLiteral.equals(BigInteger.ZERO)) {\n          return lhs;\n        } else if (lhsAsNaturalLiteral.equals(BigInteger.ONE)) {\n          return rhs;\n        }\n      } else if (rhsAsNaturalLiteral != null) {\n        if (rhsAsNaturalLiteral.equals(BigInteger.ZERO)) {\n          return rhs;\n        } else if (rhsAsNaturalLiteral.equals(BigInteger.ONE)) {\n          return lhs;\n        }\n      }\n    } else if (operator.equals(Operator.TEXT_APPEND)) {\n      String[] parts = {\"\", \"\", \"\"};\n      List<Expr> interpolated = new ArrayList(2);\n      interpolated.add(lhs);\n      interpolated.add(rhs);\n\n      return Expr.makeTextLiteral(parts, interpolated).accept(BetaNormalize.instance);\n    } else if (operator.equals(Operator.LIST_APPEND)) {\n      List<Expr> lhsAsListLiteral = Expr.Util.asListLiteral(lhs);\n      List<Expr> rhsAsListLiteral = Expr.Util.asListLiteral(rhs);\n\n      if (lhsAsListLiteral != null) {\n        if (lhsAsListLiteral.isEmpty()) {\n          return rhs;\n        } else if (rhsAsListLiteral != null) {\n          List<Expr> result = new ArrayList(lhsAsListLiteral.size() + rhsAsListLiteral.size());\n          result.addAll(lhsAsListLiteral);\n          result.addAll(rhsAsListLiteral);\n          return Expr.makeNonEmptyListLiteral(result);\n        }\n      } else if (rhsAsListLiteral != null && rhsAsListLiteral.isEmpty()) {\n        return lhs;\n      }\n    } else if (operator.equals(Operator.PREFER)) {\n      List<Entry<String, Expr>> lhsAsRecordLiteral = Expr.Util.asRecordLiteral(lhs);\n      List<Entry<String, Expr>> rhsAsRecordLiteral = Expr.Util.asRecordLiteral(rhs);\n\n      if (lhsAsRecordLiteral != null) {\n        if (rhsAsRecordLiteral != null) {\n          Map<String, Expr> asMap = new TreeMap<>();\n\n          for (Entry<String, Expr> entry : lhsAsRecordLiteral) {\n            asMap.put(entry.getKey(), entry.getValue());\n          }\n\n          for (Entry<String, Expr> entry : rhsAsRecordLiteral) {\n            asMap.put(entry.getKey(), entry.getValue());\n          }\n\n          return Expr.makeRecordLiteral(asMap.entrySet());\n        } else if (!lhsAsRecordLiteral.iterator().hasNext()) {\n          return rhs;\n        }\n\n      } else if (rhsAsRecordLiteral != null && !rhsAsRecordLiteral.iterator().hasNext()) {\n        return lhs;\n      } else if (lhs.equivalent(rhs)) {\n        return rhs;\n      }\n    } else if (operator.equals(Operator.COMPLETE)) {\n      return Expr.Util.desugarComplete(lhs, rhs).accept(BetaNormalize.instance);\n    } else if (operator.equals(Operator.COMBINE)) {\n      List<Entry<String, Expr>> firstAsRecordLiteral = Expr.Util.asRecordLiteral(lhs);\n      List<Entry<String, Expr>> secondAsRecordLiteral = Expr.Util.asRecordLiteral(rhs);\n\n      if (firstAsRecordLiteral != null) {\n        if (secondAsRecordLiteral != null) {\n          return mergeRecursive(lhs, rhs, firstAsRecordLiteral, secondAsRecordLiteral)\n              .accept(BetaNormalize.instance);\n        } else {\n          if (!firstAsRecordLiteral.iterator().hasNext()) {\n            return rhs;\n          }\n        }\n      } else if (secondAsRecordLiteral != null && !secondAsRecordLiteral.iterator().hasNext()) {\n        return lhs;\n      } else {\n        return Expr.makeOperatorApplication(Operator.COMBINE, lhs, rhs);\n      }\n\n    } else if (operator.equals(Operator.COMBINE_TYPES)) {\n      List<Entry<String, Expr>> firstAsRecordType = Expr.Util.asRecordType(lhs);\n      List<Entry<String, Expr>> secondAsRecordType = Expr.Util.asRecordType(rhs);\n\n      if (firstAsRecordType != null) {\n        if (secondAsRecordType != null) {\n          return mergeTypesRecursive(lhs, rhs, firstAsRecordType, secondAsRecordType)\n              .accept(BetaNormalize.instance);\n        } else {\n          if (!firstAsRecordType.iterator().hasNext()) {\n            return rhs;\n          }\n        }\n      } else if (secondAsRecordType != null && !secondAsRecordType.iterator().hasNext()) {\n        return lhs;\n      } else {\n        return Expr.makeOperatorApplication(Operator.COMBINE_TYPES, lhs, rhs);\n      }\n    }\n\n    return Expr.makeOperatorApplication(operator, lhs, rhs);\n  }\n\n  private static final Expr mergeRecursive(\n      Expr first,\n      Expr second,\n      List<Entry<String, Expr>> firstAsRecordLiteral,\n      List<Entry<String, Expr>> secondAsRecordLiteral) {\n    if (firstAsRecordLiteral != null && secondAsRecordLiteral != null) {\n\n      Map<String, Expr> asMap = new TreeMap<>();\n\n      for (Entry<String, Expr> entry : firstAsRecordLiteral) {\n        asMap.put(entry.getKey(), entry.getValue());\n      }\n\n      for (Entry<String, Expr> entry : secondAsRecordLiteral) {\n        String key = entry.getKey();\n        Expr value = entry.getValue();\n        Expr currentValue = asMap.get(key);\n\n        if (currentValue == null) {\n          asMap.put(key, entry.getValue());\n        } else {\n          asMap.put(\n              key,\n              mergeRecursive(\n                  currentValue,\n                  value,\n                  Expr.Util.asRecordType(currentValue),\n                  Expr.Util.asRecordType(value)));\n        }\n      }\n      return Expr.makeRecordLiteral(asMap.entrySet());\n    } else {\n      return Expr.makeOperatorApplication(Operator.COMBINE, first, second);\n    }\n  }\n\n  private static final Expr mergeTypesRecursive(\n      Expr first,\n      Expr second,\n      List<Entry<String, Expr>> firstAsRecordType,\n      List<Entry<String, Expr>> secondAsRecordType) {\n    if (firstAsRecordType != null && secondAsRecordType != null) {\n\n      Map<String, Expr> asMap = new TreeMap<>();\n\n      for (Entry<String, Expr> entry : firstAsRecordType) {\n        asMap.put(entry.getKey(), entry.getValue());\n      }\n\n      for (Entry<String, Expr> entry : secondAsRecordType) {\n        String key = entry.getKey();\n        Expr value = entry.getValue();\n        Expr currentValue = asMap.get(key);\n\n        if (currentValue == null) {\n          asMap.put(key, entry.getValue());\n        } else {\n          asMap.put(\n              key,\n              mergeTypesRecursive(\n                  currentValue,\n                  value,\n                  Expr.Util.asRecordType(currentValue),\n                  Expr.Util.asRecordType(value)));\n        }\n      }\n      return Expr.makeRecordType(asMap.entrySet());\n    } else {\n      return Expr.makeOperatorApplication(Operator.COMBINE, first, second);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeProjection.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.ExternalVisitor;\nimport org.dhallj.core.Operator;\n\nfinal class BetaNormalizeProjection extends ExternalVisitor.Constant<Expr> {\n  private final String[] fieldNames;\n\n  private BetaNormalizeProjection(String[] fieldNames) {\n    super(null);\n    this.fieldNames = fieldNames;\n  }\n\n  static final Expr apply(Expr base, final String[] fieldNames) {\n    if (fieldNames.length == 0) {\n      return Expr.Constants.EMPTY_RECORD_LITERAL;\n    }\n\n    Expr result = base.accept(new BetaNormalizeProjection(fieldNames));\n\n    if (result != null) {\n      return result;\n    } else {\n      // We have to sort the field names if we can't reduce.\n      String[] newFieldNames = new String[fieldNames.length];\n      System.arraycopy(fieldNames, 0, newFieldNames, 0, fieldNames.length);\n      Arrays.sort(newFieldNames);\n      return Expr.makeProjection(base, newFieldNames);\n    }\n  }\n\n  @Override\n  public Expr onRecord(Iterable<Entry<String, Expr>> fields, int size) {\n    Set<String> fieldNameSet = new HashSet(this.fieldNames.length);\n\n    for (String fieldName : this.fieldNames) {\n      fieldNameSet.add(fieldName);\n    }\n\n    Map<String, Expr> selected = new TreeMap();\n\n    for (Entry<String, Expr> entry : fields) {\n      if (fieldNameSet.contains(entry.getKey())) {\n        selected.put(entry.getKey(), entry.getValue());\n      }\n    }\n    return Expr.makeRecordLiteral(selected.entrySet());\n  }\n\n  @Override\n  public Expr onProjection(Expr base, String[] fieldNames) {\n    return Expr.makeProjection(base, this.fieldNames).accept(BetaNormalize.instance);\n  }\n\n  @Override\n  public Expr onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    if (operator.equals(Operator.PREFER)) {\n      List<Entry<String, Expr>> rhsFields = Expr.Util.asRecordLiteral(rhs);\n      if (rhsFields != null) {\n\n        Set<String> rhsKeys = new HashSet<String>();\n        Set<String> leftFields = new TreeSet<String>();\n        Set<String> rightFields = new TreeSet<String>();\n\n        for (Entry<String, Expr> entry : rhsFields) {\n          rhsKeys.add(entry.getKey());\n        }\n\n        for (String fieldName : this.fieldNames) {\n          if (rhsKeys.contains(fieldName)) {\n            rightFields.add(fieldName);\n          } else {\n            leftFields.add(fieldName);\n          }\n        }\n\n        return Expr.makeOperatorApplication(\n                Operator.PREFER,\n                Expr.makeProjection(lhs, leftFields.toArray(new String[leftFields.size()])),\n                Expr.makeProjection(rhs, rightFields.toArray(new String[leftFields.size()])))\n            .accept(BetaNormalize.instance);\n      }\n    }\n    return null;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeTextLiteral.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.ExternalVisitor;\n\nfinal class BetaNormalizeTextLiteral {\n  static final Expr apply(String[] parts, List<Expr> interpolated) {\n    if (parts.length == 1) {\n      return Expr.makeTextLiteral(parts[0]);\n    } else {\n      int partsSize = 0;\n      for (String part : parts) {\n        partsSize += part.length();\n      }\n      int c = 0;\n      if (partsSize == 0) {\n        Expr notEmptyString = null;\n        boolean tooMany = false;\n        Iterator<Expr> it = interpolated.iterator();\n\n        while (it.hasNext() && !tooMany) {\n          Expr next = it.next();\n          String nextAsSimpleTextLiteral = Expr.Util.asSimpleTextLiteral(next);\n\n          if (nextAsSimpleTextLiteral == null || nextAsSimpleTextLiteral.length() != 0) {\n            if (notEmptyString == null) {\n              notEmptyString = next;\n            } else {\n              tooMany = true;\n            }\n          }\n        }\n\n        if (!tooMany && notEmptyString != null) {\n          return notEmptyString;\n        }\n      }\n\n      List<String> newParts = new ArrayList<>(parts.length);\n      List<Expr> newInterpolated = new ArrayList<>(parts.length - 1);\n      newParts.add(parts[0]);\n\n      boolean wasInlined = false;\n      int partIndex = 1;\n\n      for (Expr expr : interpolated) {\n        wasInlined = expr.accept(new InlineInterpolatedTextLiteral(newParts, newInterpolated));\n\n        if (!wasInlined) {\n          newInterpolated.add(expr);\n          newParts.add(parts[partIndex++]);\n        } else {\n          int lastIndex = newParts.size() - 1;\n          String lastPart = newParts.get(lastIndex);\n          newParts.set(lastIndex, lastPart + parts[partIndex++]);\n        }\n      }\n\n      return Expr.makeTextLiteral(newParts.toArray(new String[newParts.size()]), newInterpolated);\n    }\n  }\n\n  private static final class InlineInterpolatedTextLiteral\n      extends ExternalVisitor.Constant<Boolean> {\n    private final List<String> newParts;\n    private final List<Expr> newInterpolated;\n\n    InlineInterpolatedTextLiteral(List<String> newParts, List<Expr> newInterpolated) {\n      super(false);\n      this.newParts = newParts;\n      this.newInterpolated = newInterpolated;\n    }\n\n    @Override\n    public Boolean onText(String[] parts, Iterable<Expr> interpolated) {\n      int lastIndex = newParts.size() - 1;\n      String lastPart = newParts.get(lastIndex);\n      newParts.set(lastIndex, lastPart + parts[0]);\n\n      Iterator<Expr> it = interpolated.iterator();\n\n      for (int i = 1; i < parts.length; i++) {\n        newInterpolated.add(it.next());\n        newParts.add(parts[i]);\n      }\n      return true;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeToMap.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\n\nfinal class BetaNormalizeToMap {\n  static final Expr apply(Expr base, Expr type) {\n    List<Entry<String, Expr>> baseAsRecordLiteral = Expr.Util.asRecordLiteral(base);\n\n    if (baseAsRecordLiteral != null) {\n      if (baseAsRecordLiteral.size() == 0) {\n        return Expr.makeEmptyListLiteral(type);\n      } else {\n        Expr[] result = new Expr[baseAsRecordLiteral.size()];\n\n        for (int i = 0; i < baseAsRecordLiteral.size(); i++) {\n          Entry<String, Expr> entry = baseAsRecordLiteral.get(i);\n\n          result[i] = makeRecord(entry.getKey(), entry.getValue());\n        }\n\n        return Expr.makeNonEmptyListLiteral(result);\n      }\n    } else {\n      return Expr.makeToMap(base, type);\n    }\n  }\n\n  private static final String escape(String input) {\n    StringBuilder builder = new StringBuilder();\n\n    for (int i = 0; i < input.length(); i++) {\n      char c = input.charAt(i);\n\n      if (c == '\\\\') {\n        char next = input.charAt(++i);\n\n        if (next == '\\\\') {\n          builder.append(\"\\\\\\\\\");\n        } else if (next == 'n') {\n          builder.append(\"\\\\\\\\n\");\n        } else if (next == '$') {\n          builder.append(\"\\\\\\\\\\\\$\");\n        } else {\n          builder.append(\"\\\\\\\\\");\n          builder.append(next);\n        }\n      } else {\n        builder.append(c);\n      }\n    }\n\n    return builder.toString();\n  }\n\n  private static final Expr makeRecord(String key, Expr value) {\n    Entry[] fields = {\n      new SimpleImmutableEntry<>(\n          Expr.Constants.MAP_KEY_FIELD_NAME, Expr.makeTextLiteral(escape(key))),\n      new SimpleImmutableEntry<>(Expr.Constants.MAP_VALUE_FIELD_NAME, value)\n    };\n\n    return Expr.makeRecordLiteral(fields);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/BetaNormalizeWith.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\n\nfinal class BetaNormalizeWith {\n  static final Expr apply(Expr base, String[] path, Expr value) {\n    List<Entry<String, Expr>> baseAsRecordLiteral = Expr.Util.asRecordLiteral(base);\n\n    if (baseAsRecordLiteral != null) {\n      List<Entry<String, Expr>> result = new ArrayList<>();\n      boolean found = false;\n\n      for (Entry<String, Expr> field : baseAsRecordLiteral) {\n        String key = field.getKey();\n\n        if (key.equals(path[0])) {\n          found = true;\n\n          Expr newValue;\n\n          if (path.length == 1) {\n            newValue = value;\n          } else {\n            String[] remainingPath = new String[path.length - 1];\n            System.arraycopy(path, 1, remainingPath, 0, path.length - 1);\n\n            newValue =\n                Expr.makeWith(field.getValue(), remainingPath, value)\n                    .accept(BetaNormalize.instance);\n          }\n\n          result.add(new SimpleImmutableEntry<>(key, newValue));\n        } else {\n          result.add(field);\n        }\n      }\n\n      if (!found) {\n        Expr newValue;\n\n        if (path.length == 1) {\n          newValue = value;\n        } else {\n          String[] remainingPath = new String[path.length - 1];\n          System.arraycopy(path, 1, remainingPath, 0, path.length - 1);\n\n          newValue =\n              Expr.makeWith(Expr.Constants.EMPTY_RECORD_LITERAL, remainingPath, value)\n                  .accept(BetaNormalize.instance);\n        }\n\n        result.add(new SimpleImmutableEntry<>(path[0], newValue));\n      }\n\n      Entry<String, Expr>[] resultArray = result.toArray(new Entry[result.size()]);\n\n      Arrays.sort(resultArray, entryComparator);\n\n      return Expr.makeRecordLiteral(resultArray);\n    } else {\n      return Expr.makeWith(base, path, value);\n    }\n  }\n\n  /** Java 8 introduce {@code comparingByKey}, but we can roll our own pretty easily. */\n  private static final Comparator<Entry<String, Expr>> entryComparator =\n      new Comparator<Entry<String, Expr>>() {\n        public int compare(Entry<String, Expr> a, Entry<String, Expr> b) {\n          return a.getKey().compareTo(b.getKey());\n        }\n      };\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/NormalizationUtils.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.Comparator;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\n\n/** Static utility classes and methods for internal use. */\nfinal class NormalizationUtilities {\n  static final <A> A lookup(Iterable<Entry<String, A>> entries, String key) {\n    for (Entry<String, A> entry : entries) {\n      if (entry.getKey().equals(key)) {\n        return entry.getValue();\n      }\n    }\n    return null;\n  }\n\n  static final <A> Entry<String, A> lookupEntry(Iterable<Entry<String, A>> entries, String key) {\n    for (Entry<String, A> entry : entries) {\n      if (entry.getKey().equals(key)) {\n        return entry;\n      }\n    }\n    return null;\n  }\n\n  static final Comparator<Entry<String, Expr>> entryComparator =\n      new Comparator<Entry<String, Expr>>() {\n        public int compare(Entry<String, Expr> a, Entry<String, Expr> b) {\n          return a.getKey().compareTo(b.getKey());\n        }\n      };\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/Shift.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Source;\nimport org.dhallj.core.Visitor;\n\n/**\n * Shifts all instances of a variable.\n *\n * <p>Note that this visitor maintains internal state and instances should not be reused.\n */\npublic final class Shift extends Visitor.Identity {\n  private final int change;\n  private final String name;\n  private int cutoff = 0;\n\n  public Shift(boolean isIncrement, String name) {\n    this.change = isIncrement ? 1 : -1;\n    this.name = name;\n  }\n\n  @Override\n  public Expr onIdentifier(Expr self, String name, long index) {\n    if (name.equals(this.name) && index >= this.cutoff) {\n      return Expr.makeIdentifier(name, index + this.change);\n    } else {\n      return self;\n    }\n  }\n\n  @Override\n  public void bind(String name, Expr type) {\n    if (name.equals(this.name)) {\n      this.cutoff += 1;\n    }\n  }\n\n  @Override\n  public Expr onLambda(String name, Expr type, Expr result) {\n    if (name.equals(this.name)) {\n      this.cutoff -= 1;\n    }\n\n    return Expr.makeLambda(name, type, result);\n  }\n\n  @Override\n  public Expr onPi(String name, Expr type, Expr result) {\n    if (name.equals(this.name)) {\n      this.cutoff -= 1;\n    }\n\n    return Expr.makePi(name, type, result);\n  }\n\n  @Override\n  public Expr onLet(List<Expr.LetBinding<Expr>> bindings, Expr body) {\n    for (Expr.LetBinding<Expr> binding : bindings) {\n      if (binding.getName().equals(this.name)) {\n        this.cutoff -= 1;\n      }\n    }\n    return Expr.makeLet(bindings, body);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/normalization/Substitute.java",
    "content": "package org.dhallj.core.normalization;\n\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport java.util.List;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Visitor;\n\n/**\n * Substitutes an expression for all instances of a variable in another expression.\n *\n * <p>Note that this visitor maintains internal state and instances should not be reused.\n */\npublic final class Substitute extends Visitor.Identity {\n  private final String name;\n  private int index = 0;\n  private final Deque<Expr> replacementStack = new ArrayDeque<>();\n\n  public Substitute(String name, Expr replacement) {\n    this.name = name;\n    this.replacementStack.push(replacement);\n  }\n\n  @Override\n  public void bind(String name, Expr type) {\n    this.replacementStack.push(this.replacementStack.peekFirst().increment(name));\n\n    if (name.equals(this.name)) {\n      this.index += 1;\n    }\n  }\n\n  @Override\n  public Expr onIdentifier(Expr self, String name, long index) {\n    if (name.equals(this.name)) {\n      if (index == this.index) {\n        return this.replacementStack.peekFirst();\n      } else if (index > this.index) {\n        return Expr.makeIdentifier(name, index - 1);\n      } else {\n        return self;\n      }\n    } else {\n      return self;\n    }\n  }\n\n  @Override\n  public Expr onLambda(String name, Expr type, Expr result) {\n    this.replacementStack.pop();\n\n    if (name.equals(this.name)) {\n      this.index -= 1;\n    }\n\n    return Expr.makeLambda(name, type, result);\n  }\n\n  @Override\n  public Expr onPi(String name, Expr type, Expr result) {\n    this.replacementStack.pop();\n\n    if (name.equals(this.name)) {\n      this.index -= 1;\n    }\n\n    return Expr.makePi(name, type, result);\n  }\n\n  @Override\n  public Expr onLet(List<Expr.LetBinding<Expr>> bindings, Expr body) {\n    for (Expr.LetBinding<Expr> binding : bindings) {\n      String name = binding.getName();\n\n      this.replacementStack.pop();\n\n      if (name.equals(this.name)) {\n        this.index -= 1;\n      }\n    }\n    return Expr.makeLet(bindings, body);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/BuiltInTypes.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Expr.Constants;\n\nfinal class BuiltInTypes {\n  static final Expr getType(String name) {\n    return mappings.get(name);\n  }\n\n  private static final int SIZE = 34;\n  private static final Map<String, Expr> mappings = new HashMap<>(SIZE);\n\n  static {\n    Expr typeToType = Expr.makePi(Constants.TYPE, Constants.TYPE);\n    Expr naturalToBool = Expr.makePi(Constants.NATURAL, Constants.BOOL);\n    Expr naturalToNatural = Expr.makePi(Constants.NATURAL, Constants.NATURAL);\n    Expr _natural = Expr.makeIdentifier(\"natural\");\n    Expr naturalType =\n        Expr.makePi(\n            \"natural\",\n            Constants.TYPE,\n            Expr.makePi(\n                \"succ\", Expr.makePi(_natural, _natural), Expr.makePi(\"zero\", _natural, _natural)));\n    Expr _a = Expr.makeIdentifier(\"a\");\n    Expr listA = Expr.makeApplication(Constants.LIST, _a);\n    Expr optionalA = Expr.makeApplication(Constants.OPTIONAL, _a);\n    Expr listAToOptionalA = Expr.makePi(\"a\", Expr.Constants.TYPE, Expr.makePi(listA, optionalA));\n\n    Expr _list = Expr.makeIdentifier(\"list\");\n    Expr listType =\n        Expr.makePi(\n            \"list\",\n            Constants.TYPE,\n            Expr.makePi(\n                \"cons\",\n                Expr.makePi(_a, Expr.makePi(_list, _list)),\n                Expr.makePi(\"nil\", _list, _list)));\n\n    mappings.put(\"Kind\", Constants.SORT);\n    mappings.put(\"Type\", Constants.KIND);\n    mappings.put(\"Bool\", Constants.TYPE);\n    mappings.put(\"True\", Constants.BOOL);\n    mappings.put(\"False\", Constants.BOOL);\n    mappings.put(\"Natural\", Constants.TYPE);\n    mappings.put(\"Integer\", Constants.TYPE);\n    mappings.put(\"Text\", Constants.TYPE);\n    mappings.put(\"Double\", Constants.TYPE);\n    mappings.put(\"List\", typeToType);\n    mappings.put(\"Optional\", typeToType);\n    mappings.put(\n        \"None\",\n        Expr.makePi(\n            \"A\",\n            Constants.TYPE,\n            Expr.makeApplication(Constants.OPTIONAL, Expr.makeIdentifier(\"A\"))));\n\n    mappings.put(\n        \"Text/replace\",\n        Expr.makePi(\n            \"needle\",\n            Constants.TEXT,\n            Expr.makePi(\n                \"replacement\",\n                Constants.TEXT,\n                Expr.makePi(\"haystack\", Constants.TEXT, Constants.TEXT))));\n    mappings.put(\"Text/show\", Expr.makePi(Constants.TEXT, Constants.TEXT));\n\n    mappings.put(\"Natural/build\", Expr.makePi(naturalType, Constants.NATURAL));\n    mappings.put(\"Natural/fold\", Expr.makePi(Constants.NATURAL, naturalType));\n    mappings.put(\"Natural/isZero\", naturalToBool);\n    mappings.put(\"Natural/even\", naturalToBool);\n    mappings.put(\"Natural/odd\", naturalToBool);\n    mappings.put(\"Natural/toInteger\", Expr.makePi(Constants.NATURAL, Constants.INTEGER));\n    mappings.put(\"Natural/show\", Expr.makePi(Constants.NATURAL, Constants.TEXT));\n    mappings.put(\"Natural/subtract\", Expr.makePi(Constants.NATURAL, naturalToNatural));\n\n    mappings.put(\"Integer/show\", Expr.makePi(Constants.INTEGER, Constants.TEXT));\n    mappings.put(\"Integer/toDouble\", Expr.makePi(Constants.INTEGER, Constants.DOUBLE));\n    mappings.put(\"Integer/negate\", Expr.makePi(Constants.INTEGER, Constants.INTEGER));\n    mappings.put(\"Integer/clamp\", Expr.makePi(Constants.INTEGER, Constants.NATURAL));\n\n    mappings.put(\"Double/show\", Expr.makePi(Constants.DOUBLE, Constants.TEXT));\n\n    mappings.put(\"List/build\", Expr.makePi(\"a\", Constants.TYPE, Expr.makePi(listType, listA)));\n    mappings.put(\"List/fold\", Expr.makePi(\"a\", Constants.TYPE, Expr.makePi(listA, listType)));\n    mappings.put(\n        \"List/length\",\n        Expr.makePi(\"a\", Expr.Constants.TYPE, Expr.makePi(listA, Constants.NATURAL)));\n    mappings.put(\"List/head\", listAToOptionalA);\n    mappings.put(\"List/last\", listAToOptionalA);\n\n    Entry[] indexedRecordFields = {\n      new SimpleImmutableEntry<>(\"index\", Constants.NATURAL),\n      new SimpleImmutableEntry<>(\"value\", _a)\n    };\n\n    mappings.put(\n        \"List/indexed\",\n        Expr.makePi(\n            \"a\",\n            Constants.TYPE,\n            Expr.makePi(\n                listA,\n                Expr.makeApplication(Constants.LIST, Expr.makeRecordType(indexedRecordFields)))));\n    mappings.put(\"List/reverse\", Expr.makePi(\"a\", Constants.TYPE, Expr.makePi(listA, listA)));\n\n    mappings.put(\"Some\", Constants.SOME);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/CheckEquivalence.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.ExternalVisitor;\n\nfinal class CheckEquivalence extends ExternalVisitor.Constant<Boolean> {\n  public static final ExternalVisitor<Boolean> instance = new CheckEquivalence();\n\n  CheckEquivalence() {\n    super(null);\n  }\n\n  @Override\n  public Boolean onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    return operator.equals(Operator.EQUIVALENT) && lhs.equivalent(rhs);\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/Context.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport org.dhallj.core.Expr;\n\nfinal class Context {\n  private final String key;\n  private final Expr value;\n  private final Context tail;\n\n  Context(String key, Expr value, Context tail) {\n    this.key = key;\n    this.value = value;\n    this.tail = tail;\n  }\n\n  public Expr lookup(String targetKey, long index) {\n    if (this.key != null && this.key.equals(targetKey)) {\n      if (index == 0) {\n        return this.value;\n      } else {\n        if (this.tail == null) {\n          return null;\n        } else {\n          return this.tail.lookup(targetKey, index - 1);\n        }\n      }\n    } else {\n      if (this.tail == null) {\n        return null;\n      } else {\n        return this.tail.lookup(targetKey, index);\n      }\n    }\n  }\n\n  public Context insert(String key, Expr value) {\n    return new Context(key, value, this);\n  }\n\n  public Context increment(String name) {\n    if (this.key == null) {\n      return this;\n    } else {\n      return new Context(this.key, this.value.increment(name), this.tail.increment(name));\n    }\n  }\n\n  public Context decrement(String name) {\n    if (this.key == null) {\n      return this;\n    } else {\n      return new Context(this.key, this.value.decrement(name), this.tail.decrement(name));\n    }\n  }\n\n  public static final Context EMPTY = new Context(null, null, null);\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/NonNegativeIndices.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Visitor;\n\nfinal class NonNegativeIndices extends Visitor.Property {\n  public static final Visitor<Boolean> instance = new NonNegativeIndices();\n\n  @Override\n  public Boolean onIdentifier(Expr self, String name, long index) {\n    return index >= 0;\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/TypeCheck.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.ExternalVisitor;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Source;\nimport org.dhallj.core.Expr.Constants;\nimport org.dhallj.core.normalization.BetaNormalize;\n\npublic final class TypeCheck implements ExternalVisitor<Expr> {\n  private Context context;\n\n  public TypeCheck(Context context) {\n    this.context = context;\n  }\n\n  public TypeCheck() {\n    this(Context.EMPTY);\n  }\n\n  @Override\n  public final Expr onNote(Expr base, Source source) {\n    return base.accept(this);\n  }\n\n  @Override\n  public final Expr onNatural(BigInteger value) {\n    return Constants.NATURAL;\n  }\n\n  @Override\n  public final Expr onInteger(BigInteger value) {\n    return Constants.INTEGER;\n  }\n\n  @Override\n  public final Expr onDouble(double value) {\n    return Constants.DOUBLE;\n  }\n\n  @Override\n  public final Expr onDate(int year, int month, int day) {\n    return Constants.DATE;\n  }\n\n  @Override\n  public final Expr onTime(int hour, int minute, int second, BigDecimal fractional) {\n    return Constants.TIME;\n  }\n\n  @Override\n  public final Expr onTimeZone(int minutes) {\n    return Constants.TIME_ZONE;\n  }\n\n  @Override\n  public final Expr onBuiltIn(String name) {\n    if (name.equals(\"Sort\")) {\n      throw TypeCheckFailure.makeSortError();\n    } else {\n      Expr type = BuiltInTypes.getType(name);\n      if (type != null) {\n        return type;\n      } else {\n        throw TypeCheckFailure.makeUnboundVariableError(name);\n      }\n    }\n  }\n\n  @Override\n  public final Expr onIdentifier(String name, long index) {\n    Expr fromContext = this.context.lookup(name, index);\n\n    if (fromContext != null) {\n      return fromContext;\n    } else {\n      throw TypeCheckFailure.makeUnboundVariableError(name);\n    }\n  }\n\n  @Override\n  public final Expr onLambda(String param, Expr input, Expr result) {\n    Expr inputType = input.accept(this);\n    if (Universe.fromExpr(inputType) != null) {\n      Context unshiftedContext = this.context;\n      Expr inputNormalized = input.accept(BetaNormalize.instance);\n      this.context = this.context.insert(param, inputNormalized).increment(param);\n      Expr resultType = result.accept(this);\n      this.context = unshiftedContext;\n      return Expr.makePi(param, inputNormalized, resultType);\n    } else {\n      throw TypeCheckFailure.makeLambdaInputError(inputType);\n    }\n  }\n\n  @Override\n  public final Expr onPi(String param, Expr input, Expr result) {\n    Expr inputType = input.accept(this);\n    Context unshiftedContext = this.context;\n    this.context = this.context.insert(param, input).increment(param);\n    Expr resultType = result.accept(this);\n    this.context = unshiftedContext;\n\n    Universe inputTypeUniverse = Universe.fromExpr(inputType);\n\n    if (inputTypeUniverse == null) {\n      throw TypeCheckFailure.makePiInputError(inputType);\n    }\n\n    Universe resultTypeUniverse = Universe.fromExpr(resultType);\n\n    if (resultTypeUniverse == null) {\n      throw TypeCheckFailure.makePiOutputError(resultType);\n    }\n\n    return Universe.functionCheck(inputTypeUniverse, resultTypeUniverse).toExpr();\n  }\n\n  @Override\n  public final Expr onLet(String name, Expr type, Expr value, Expr body) {\n    Expr valueType = value.accept(this);\n\n    if (type != null) {\n      // We must confirm that the annotation is well-typed.\n      type.accept(this);\n\n      if (!type.equivalent(valueType)) {\n        throw TypeCheckFailure.makeAnnotationError(type, valueType);\n      }\n    }\n\n    return body.substitute(name, value.accept(BetaNormalize.instance)).accept(this);\n  }\n\n  @Override\n  public final Expr onText(String[] parts, Iterable<Expr> interpolated) {\n    for (Expr expr : interpolated) {\n      Expr exprType = expr.accept(this);\n      if (!isText(exprType)) {\n        throw TypeCheckFailure.makeInterpolationError(expr, exprType);\n      }\n    }\n\n    return Constants.TEXT;\n  }\n\n  @Override\n  public final Expr onNonEmptyList(Iterable<Expr> values, int size) {\n    Iterator<Expr> it = values.iterator();\n    Expr firstType = it.next().accept(this);\n\n    if (isType(firstType.accept(this))) {\n      while (it.hasNext()) {\n        Expr elementType = it.next().accept(this);\n        if (!elementType.equivalent(firstType)) {\n          throw TypeCheckFailure.makeListTypeMismatchError(firstType, elementType);\n        }\n      }\n\n      return Expr.makeApplication(Expr.Constants.LIST, firstType);\n    } else {\n      throw TypeCheckFailure.makeListTypeError(firstType);\n    }\n  }\n\n  @Override\n  public final Expr onEmptyList(Expr type) {\n    // We verify that the type is well-typed.\n    type.accept(this);\n\n    Expr typeNormalized = type.accept(BetaNormalize.instance);\n    Expr elementType = Expr.Util.getListArg(typeNormalized);\n\n    if (elementType != null && isType(elementType.accept(this))) {\n      return Expr.makeApplication(Constants.LIST, elementType);\n    } else {\n      throw TypeCheckFailure.makeListTypeError(elementType);\n    }\n  }\n\n  @Override\n  public final Expr onRecord(Iterable<Entry<String, Expr>> fields, int size) {\n    if (size == 0) {\n      return Constants.EMPTY_RECORD_TYPE;\n    } else {\n      Map<String, Expr> fieldTypes = new TreeMap<>();\n\n      for (Entry<String, Expr> field : fields) {\n        fieldTypes.put(\n            field.getKey(), field.getValue().accept(this).accept(BetaNormalize.instance));\n      }\n\n      Expr recordType = Expr.makeRecordType(fieldTypes.entrySet());\n\n      // The inferred type must also be well-typed.\n      recordType.accept(this);\n      return recordType;\n    }\n  }\n\n  @Override\n  public final Expr onRecordType(Iterable<Entry<String, Expr>> fields, int size) {\n    // Need to check for duplicates here; see: https://github.com/travisbrown/dhallj/issues/6\n    Set<String> fieldNamesSeen = new HashSet<>(size);\n\n    Universe max = Universe.TYPE;\n\n    for (Entry<String, Expr> field : fields) {\n      String fieldName = field.getKey();\n\n      if (!fieldNamesSeen.add(fieldName)) {\n        throw TypeCheckFailure.makeFieldDuplicateError(fieldName);\n      }\n\n      Expr type = field.getValue().accept(this);\n      Universe universe = Universe.fromExpr(type);\n\n      if (universe != null) {\n        max = max.max(universe);\n      } else {\n        throw TypeCheckFailure.makeFieldTypeError(fieldName, type);\n      }\n    }\n\n    return max.toExpr();\n  }\n\n  @Override\n  public final Expr onUnionType(Iterable<Entry<String, Expr>> fields, int size) {\n    Set<String> fieldNamesSeen = new HashSet<>(size);\n\n    Universe max = Universe.TYPE;\n\n    for (Entry<String, Expr> field : fields) {\n      String fieldName = field.getKey();\n\n      if (!fieldNamesSeen.add(fieldName)) {\n        throw TypeCheckFailure.makeAlternativeDuplicateError(fieldName);\n      }\n\n      Expr alternativeType = field.getValue();\n\n      if (alternativeType != null) {\n        Expr type = alternativeType.accept(this);\n        Universe universe = Universe.fromExpr(type);\n\n        if (universe != null) {\n          max = max.max(universe);\n        } else {\n          throw TypeCheckFailure.makeAlternativeTypeError(fieldName, type);\n        }\n      }\n    }\n\n    return max.toExpr();\n  }\n\n  @Override\n  public final Expr onFieldAccess(Expr base, String fieldName) {\n    Expr baseType = base.accept(this);\n    List<Entry<String, Expr>> fields = Expr.Util.asRecordType(baseType);\n\n    if (fields != null) {\n      for (Entry<String, Expr> field : fields) {\n        if (field.getKey().equals(fieldName)) {\n          return field.getValue();\n        }\n      }\n      throw TypeCheckFailure.makeFieldAccessRecordMissingError(fieldName);\n    } else {\n      Expr baseNormalized = base.accept(BetaNormalize.instance);\n      List<Entry<String, Expr>> alternatives = Expr.Util.asUnionType(baseNormalized);\n      if (alternatives != null) {\n        for (Entry<String, Expr> alternative : alternatives) {\n          if (alternative.getKey().equals(fieldName)) {\n            if (alternative.getValue() == null) {\n              return baseNormalized;\n            } else {\n              return Expr.makePi(fieldName, alternative.getValue(), baseNormalized);\n            }\n          }\n        }\n        throw TypeCheckFailure.makeFieldAccessUnionMissingError(fieldName);\n      } else {\n        throw TypeCheckFailure.makeFieldAccessError();\n      }\n    }\n  }\n\n  @Override\n  public final Expr onProjection(Expr base, String[] fieldNames) {\n    List<Entry<String, Expr>> fields = Expr.Util.asRecordType(base.accept(this));\n\n    if (fields != null) {\n      Map<String, Expr> fieldMap = new HashMap<>();\n\n      for (Entry<String, Expr> field : fields) {\n        fieldMap.put(field.getKey(), field.getValue());\n      }\n\n      List<Entry<String, Expr>> newFields = new ArrayList();\n      List<String> missing = null;\n\n      for (String fieldName : fieldNames) {\n        Expr value = fieldMap.remove(fieldName);\n\n        if (value == null) {\n          if (missing == null) {\n            missing = new ArrayList<>();\n          }\n          missing.add(fieldName);\n        } else {\n          newFields.add(new SimpleImmutableEntry<>(fieldName, value));\n        }\n      }\n\n      if (missing == null) {\n        return Expr.makeRecordType(newFields);\n      } else {\n        throw TypeCheckFailure.makeFieldAccessRecordMissingError(missing.get(0));\n      }\n    } else {\n      throw TypeCheckFailure.makeProjectionError();\n    }\n  }\n\n  @Override\n  public final Expr onProjectionByType(Expr base, Expr type) {\n    List<Entry<String, Expr>> fields = Expr.Util.asRecordType(base.accept(this));\n\n    if (fields == null) {\n      throw TypeCheckFailure.makeProjectionError();\n    } else {\n      List<Entry<String, Expr>> projected =\n          Expr.Util.asRecordType(type.accept(BetaNormalize.instance));\n\n      if (projected == null) {\n        throw TypeCheckFailure.makeProjectionError();\n      } else {\n        Map<String, Expr> fieldMap = new HashMap<>();\n\n        for (Entry<String, Expr> field : fields) {\n          fieldMap.put(field.getKey(), field.getValue());\n        }\n\n        for (Entry<String, Expr> projectedEntry : projected) {\n          String fieldName = projectedEntry.getKey();\n          Expr value = fieldMap.get(fieldName);\n          Expr projectedValue = projectedEntry.getValue();\n\n          if (value == null || !value.equivalent(projectedValue)) {\n            throw TypeCheckFailure.makeFieldAccessRecordMissingError(fieldName);\n          }\n        }\n\n        return Expr.makeRecordType(projected);\n      }\n    }\n  }\n\n  @Override\n  public final Expr onApplication(Expr base, Expr arg) {\n    Expr baseType = base.accept(this);\n    Expr argType = arg.accept(this);\n\n    Expr result = baseType.accept(new TypeCheckApplication(arg, argType, this));\n\n    if (result != null) {\n      return result;\n    } else {\n      throw TypeCheckFailure.makeApplicationError(base, arg);\n    }\n  }\n\n  @Override\n  public final Expr onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    Expr lhsType = lhs.accept(this);\n    Expr rhsType = rhs.accept(this);\n    switch (operator) {\n      case OR:\n      case AND:\n      case EQUALS:\n      case NOT_EQUALS:\n        if (isBool(lhsType) && isBool(rhsType)) {\n          return Constants.BOOL;\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n      case PLUS:\n      case TIMES:\n        if (isNatural(lhsType) && isNatural(rhsType)) {\n          return Constants.NATURAL;\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n      case TEXT_APPEND:\n        if (isText(lhsType) && isText(rhsType)) {\n          return Constants.TEXT;\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n      case LIST_APPEND:\n        Expr lhsListElementType = Expr.Util.getListArg(lhsType);\n        Expr rhsListElementType = Expr.Util.getListArg(rhsType);\n\n        if (lhsListElementType != null && rhsListElementType != null) {\n          if (lhsListElementType.equivalent(rhsListElementType)) {\n            return lhsType;\n          } else {\n            throw TypeCheckFailure.makeListAppendError(lhsListElementType, rhsListElementType);\n          }\n\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n      case COMBINE:\n        Expr combineTypes = Expr.makeOperatorApplication(Operator.COMBINE_TYPES, lhsType, rhsType);\n\n        // Type-check the type-level version, although we don't use the result;\n        try {\n          combineTypes.accept(this);\n        } catch (TypeCheckFailure e) {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n\n        return combineTypes.accept(BetaNormalize.instance);\n      case PREFER:\n        List<Entry<String, Expr>> lhsTypeRecordType = Expr.Util.asRecordType(lhsType);\n        List<Entry<String, Expr>> rhsTypeRecordType = Expr.Util.asRecordType(rhsType);\n\n        if (lhsTypeRecordType != null && rhsTypeRecordType != null) {\n          return Expr.makeRecordType(prefer(lhsTypeRecordType, rhsTypeRecordType));\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n      case COMBINE_TYPES:\n        List<Entry<String, Expr>> lhsRecordType =\n            Expr.Util.asRecordType(lhs.accept(BetaNormalize.instance));\n        List<Entry<String, Expr>> rhsRecordType =\n            Expr.Util.asRecordType(rhs.accept(BetaNormalize.instance));\n\n        if (lhsRecordType != null && rhsRecordType != null) {\n          if (isType(rhsType) && !rhsRecordType.iterator().hasNext()) {\n            return lhsType;\n          } else {\n            Universe lhsTypeUniverse = Universe.fromExpr(lhsType);\n            Universe rhsTypeUniverse = Universe.fromExpr(rhsType);\n\n            if (lhsTypeUniverse != null && rhsTypeUniverse != null) {\n              // TODO: report collisions correctly.\n              checkRecursiveTypeMerge(lhsRecordType, rhsRecordType);\n\n              return lhsTypeUniverse.max(rhsTypeUniverse).toExpr();\n            } else {\n              throw TypeCheckFailure.makeOperatorError(operator);\n            }\n          }\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n      case IMPORT_ALT:\n        // TODO: Confirm that this is correct.\n        return lhsType.accept(this);\n      case EQUIVALENT:\n        Expr lhsTypeType = lhsType.accept(this);\n        Expr rhsTypeType = rhsType.accept(this);\n\n        if (lhsTypeType != null\n            && rhsTypeType != null\n            && isType(lhsTypeType)\n            && isType(rhsTypeType)) {\n          if (lhsType.equivalent(rhsType)) {\n            return Constants.TYPE;\n          } else {\n            throw TypeCheckFailure.makeEquivalenceError(lhsType, rhsType);\n          }\n        } else {\n          throw TypeCheckFailure.makeOperatorError(operator);\n        }\n\n      case COMPLETE:\n        return Expr.Util.desugarComplete(lhs, rhs).accept(this);\n      default:\n        return null;\n    }\n  }\n\n  @Override\n  public final Expr onIf(Expr predicate, Expr thenValue, Expr elseValue) {\n    Expr predicateType = predicate.accept(this);\n    if (isBool(predicateType)) {\n      Expr thenType = thenValue.accept(this);\n      Expr elseType = elseValue.accept(this);\n\n      if (thenType.equals(Expr.Constants.SORT) || elseType.equals(Expr.Constants.SORT)) {\n        throw TypeCheckFailure.makeSortError();\n      }\n\n      if (thenType.equivalent(elseType)) {\n        return thenType;\n      } else {\n        throw TypeCheckFailure.makeIfBranchTypeMismatchError(thenType, elseType);\n      }\n    } else {\n      throw TypeCheckFailure.makeIfPredicateError(predicateType);\n    }\n  }\n\n  @Override\n  public final Expr onAnnotated(Expr base, Expr type) {\n    Expr inferredType = base.accept(this);\n    if (inferredType.equivalent(type)) {\n      return inferredType;\n    } else {\n      throw TypeCheckFailure.makeAnnotationError(type, inferredType);\n    }\n  }\n\n  @Override\n  public final Expr onAssert(Expr base) {\n    Expr baseType = base.accept(this);\n\n    if (isType(baseType)) {\n      Expr normalized = base.accept(BetaNormalize.instance);\n      Boolean isEquivalent = normalized.accept(CheckEquivalence.instance);\n      if (isEquivalent != null && isEquivalent) {\n        return normalized;\n      }\n    }\n    throw TypeCheckFailure.makeAssertError(base);\n  }\n\n  @Override\n  public final Expr onMerge(Expr handlers, Expr union, Expr type) {\n    Expr handlersType = handlers.accept(this);\n    List<Entry<String, Expr>> handlersTypeFields = Expr.Util.asRecordType(handlersType);\n\n    if (handlersTypeFields == null) {\n      // The handlers argument is not a record.\n      throw TypeCheckFailure.makeMergeHandlersTypeError(handlersType);\n    } else {\n      Expr unionType = union.accept(this);\n      List<Entry<String, Expr>> unionTypeFields = Expr.Util.asUnionType(unionType);\n\n      if (unionTypeFields != null) {\n        Expr inferredType = getMergeInferredType(handlersTypeFields, unionTypeFields);\n\n        if (inferredType != null) {\n          if (type == null || inferredType.equivalent(type)) {\n            return inferredType;\n          } else {\n            throw TypeCheckFailure.makeMergeInvalidAnnotationError(type, inferredType);\n          }\n        } else if (type != null) {\n          return type;\n        } else {\n          // Both were empty (this shouldn't happen).\n          throw TypeCheckFailure.makeMergeUnionTypeError(type);\n        }\n      } else {\n        Expr optionalElementType = Expr.Util.getOptionalArg(unionType);\n        if (optionalElementType == null) {\n          throw TypeCheckFailure.makeMergeUnionTypeError(unionType);\n        } else {\n          Expr inferredType =\n              getMergeInferredType(\n                  handlersTypeFields, makeOptionalConstructors(optionalElementType));\n\n          if (inferredType != null) {\n            if (type == null || inferredType.equivalent(type)) {\n              return inferredType;\n            } else {\n              throw TypeCheckFailure.makeMergeInvalidAnnotationError(type, inferredType);\n            }\n          } else if (type != null) {\n            return type;\n          } else {\n            // Both were empty (this shouldn't happen).\n            throw TypeCheckFailure.makeMergeUnionTypeError(type);\n          }\n        }\n      }\n    }\n  }\n\n  @Override\n  public final Expr onToMap(Expr base, Expr type) {\n    Expr baseType = base.accept(this);\n    List<Entry<String, Expr>> baseAsRecord = Expr.Util.asRecordType(baseType);\n\n    if (baseAsRecord == null) {\n      throw TypeCheckFailure.makeToMapTypeError(baseType);\n    } else {\n      Expr firstType = null;\n\n      for (Entry<String, Expr> entry : baseAsRecord) {\n        Expr fieldType = entry.getValue();\n\n        if (!isType(fieldType.accept(this))) {\n          throw TypeCheckFailure.makeToMapRecordKindError(fieldType);\n        } else {\n          if (firstType == null) {\n            firstType = fieldType;\n          } else {\n            if (!fieldType.equivalent(firstType)) {\n              throw TypeCheckFailure.makeToMapRecordTypeMismatchError(firstType, fieldType);\n            }\n          }\n        }\n      }\n\n      // The input record is non-empty.\n      if (firstType != null) {\n        Entry[] inferredTypeFields = {\n          new SimpleImmutableEntry<>(Constants.MAP_KEY_FIELD_NAME, Constants.TEXT),\n          new SimpleImmutableEntry<>(Constants.MAP_VALUE_FIELD_NAME, firstType)\n        };\n\n        Expr inferredType =\n            Expr.makeApplication(Constants.LIST, Expr.makeRecordType(inferredTypeFields));\n\n        if (type == null || type.equivalent(inferredType)) {\n          return inferredType;\n        } else {\n          throw TypeCheckFailure.makeToMapResultTypeMismatchError(type, inferredType);\n        }\n      } else {\n        if (type == null) {\n          throw TypeCheckFailure.makeToMapMissingAnnotationError();\n        } else {\n          Expr typeType = type.accept(this);\n\n          if (!isType(typeType)) {\n            throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n          } else {\n            Expr typeNormalized = type.accept(BetaNormalize.instance);\n            Expr listElementType = Expr.Util.getListArg(typeNormalized);\n\n            if (listElementType == null) {\n              throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n            } else {\n              List<Entry<String, Expr>> typeFields = Expr.Util.asRecordType(listElementType);\n\n              if (typeFields == null) {\n                throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n              } else {\n                boolean sawKey = false;\n                boolean sawValue = false;\n\n                for (Entry<String, Expr> typeField : typeFields) {\n                  if (sawKey && sawValue) {\n                    throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n                  } else {\n                    if (typeField.getKey().equals(Constants.MAP_KEY_FIELD_NAME)) {\n                      if (isText(typeField.getValue())) {\n                        sawKey = true;\n                      } else {\n                        throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n                      }\n                    } else if (typeField.getKey().equals(Constants.MAP_VALUE_FIELD_NAME)) {\n                      sawValue = true;\n                    } else {\n                      throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n                    }\n                  }\n                }\n\n                if (sawKey && sawValue) {\n                  return typeNormalized;\n                } else {\n                  throw TypeCheckFailure.makeToMapInvalidAnnotationError(type);\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n\n  @Override\n  public final Expr onWith(Expr base, String[] path, Expr value) {\n    List<Entry<String, Expr>> baseAsRecordLiteral = Expr.Util.asRecordLiteral(base);\n\n    if (baseAsRecordLiteral == null) {\n      throw TypeCheckFailure.makeWithTypeError(base.accept(this));\n    } else {\n      List<Entry<String, Expr>> result = new ArrayList<>();\n      boolean found = false;\n\n      for (Entry<String, Expr> field : baseAsRecordLiteral) {\n        String key = field.getKey();\n\n        if (key.equals(path[0])) {\n          found = true;\n\n          Expr newValue;\n\n          if (path.length == 1) {\n            newValue = value.accept(this);\n          } else {\n            String[] remainingPath = new String[path.length - 1];\n            System.arraycopy(path, 1, remainingPath, 0, path.length - 1);\n\n            newValue = Expr.makeWith(field.getValue(), remainingPath, value).accept(this);\n          }\n\n          result.add(new SimpleImmutableEntry<>(key, newValue));\n        } else {\n          result.add(new SimpleImmutableEntry<>(key, field.getValue().accept(this)));\n        }\n      }\n\n      if (!found) {\n        Expr newValue;\n\n        if (path.length == 1) {\n          newValue = value.accept(this);\n        } else {\n          String[] remainingPath = new String[path.length - 1];\n          System.arraycopy(path, 1, remainingPath, 0, path.length - 1);\n\n          newValue =\n              Expr.makeWith(Expr.Constants.EMPTY_RECORD_LITERAL, remainingPath, value).accept(this);\n        }\n\n        result.add(new SimpleImmutableEntry<>(path[0], newValue));\n      }\n\n      Entry<String, Expr>[] resultArray = result.toArray(new Entry[result.size()]);\n\n      Arrays.sort(resultArray, entryComparator);\n\n      return Expr.makeRecordType(resultArray);\n    }\n  }\n\n  @Override\n  public final Expr onMissingImport(Expr.ImportMode mode, byte[] hash) {\n    throw TypeCheckFailure.makeUnresolvedImportError();\n  }\n\n  @Override\n  public final Expr onEnvImport(String value, Expr.ImportMode mode, byte[] hash) {\n    throw TypeCheckFailure.makeUnresolvedImportError();\n  }\n\n  @Override\n  public final Expr onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    throw TypeCheckFailure.makeUnresolvedImportError();\n  }\n\n  @Override\n  public final Expr onClasspathImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    throw TypeCheckFailure.makeUnresolvedImportError();\n  }\n\n  @Override\n  public final Expr onRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n    throw TypeCheckFailure.makeUnresolvedImportError();\n  }\n\n  static final boolean isBool(Expr expr) {\n    String asBuiltIn = Expr.Util.asBuiltIn(expr);\n    return asBuiltIn != null && asBuiltIn.equals(\"Bool\");\n  }\n\n  static final boolean isText(Expr expr) {\n    String asBuiltIn = Expr.Util.asBuiltIn(expr);\n    return asBuiltIn != null && asBuiltIn.equals(\"Text\");\n  }\n\n  static final boolean isList(Expr expr) {\n    String asBuiltIn = Expr.Util.asBuiltIn(expr);\n    return asBuiltIn != null && asBuiltIn.equals(\"List\");\n  }\n\n  static final boolean isNatural(Expr expr) {\n    String asBuiltIn = Expr.Util.asBuiltIn(expr);\n    return asBuiltIn != null && asBuiltIn.equals(\"Natural\");\n  }\n\n  static final boolean isOptional(Expr expr) {\n    String asBuiltIn = Expr.Util.asBuiltIn(expr);\n    return asBuiltIn != null && asBuiltIn.equals(\"Optional\");\n  }\n\n  static final boolean isType(Expr expr) {\n    String asBuiltIn = Expr.Util.asBuiltIn(expr);\n    return asBuiltIn != null && asBuiltIn.equals(\"Type\");\n  }\n\n  private final void checkRecursiveTypeMerge(\n      List<Entry<String, Expr>> lhs, List<Entry<String, Expr>> rhs) {\n\n    Map<String, Expr> lhsMap = new HashMap<>();\n\n    for (Entry<String, Expr> entry : lhs) {\n      lhsMap.put(entry.getKey(), entry.getValue());\n    }\n\n    for (Entry<String, Expr> entry : rhs) {\n      Expr rhsValue = entry.getValue();\n      Expr lhsValue = lhsMap.get(entry.getKey());\n\n      if (lhsValue != null) {\n        Expr.makeOperatorApplication(Operator.COMBINE_TYPES, lhsValue, rhsValue).accept(this);\n      }\n    }\n  }\n\n  private static final List<Entry<String, Expr>> makeOptionalConstructors(Expr type) {\n    List<Entry<String, Expr>> constructors = new ArrayList<>();\n    constructors.add((Entry<String, Expr>) new SimpleImmutableEntry<>(\"None\", (Expr) null));\n    constructors.add((Entry<String, Expr>) new SimpleImmutableEntry<>(\"Some\", type));\n    return constructors;\n  }\n\n  private static final Expr getMergeInferredType(\n      List<Entry<String, Expr>> handlerTypes, List<Entry<String, Expr>> constructors) {\n    Map<String, Expr> handlerTypeMap = new HashMap<>();\n\n    for (Entry<String, Expr> handlerTypeField : handlerTypes) {\n      handlerTypeMap.put(handlerTypeField.getKey(), handlerTypeField.getValue());\n    }\n\n    Expr resultType = null;\n\n    for (Entry<String, Expr> constructor : constructors) {\n      String fieldName = constructor.getKey();\n      Expr handlerType = handlerTypeMap.remove(fieldName);\n\n      if (handlerType == null) {\n        throw TypeCheckFailure.makeMergeHandlerMissingError(fieldName);\n      } else {\n        final Expr constructorType = constructor.getValue();\n\n        if (constructorType == null) {\n          // We have an empty constructor.\n          if (resultType == null) {\n            // This is the first constructor.\n            resultType = handlerType;\n          } else {\n            // We check that the handler type is the same as previous result types.\n            if (!handlerType.equivalent(resultType)) {\n              throw TypeCheckFailure.makeMergeHandlerTypeMismatchError(resultType, handlerType);\n            }\n          }\n        } else {\n          // We have a constructor with a type, so we have to make sure the handler is a function.\n          Expr handlerResultType =\n              handlerType.accept(\n                  new ExternalVisitor.Constant<Expr>(null) {\n                    public Expr onPi(String name, Expr input, Expr result) {\n                      if (!input.equivalent(constructorType)) {\n                        throw TypeCheckFailure.makeMergeHandlerTypeInvalidError(\n                            constructorType, input);\n                      } else {\n                        Expr inferredResultType = result.decrement(name);\n\n                        if (!inferredResultType.accept(NonNegativeIndices.instance)) {\n                          throw TypeCheckFailure.makeMergeHandlerTypeDisallowedError(\n                              inferredResultType);\n                        }\n\n                        return inferredResultType;\n                      }\n                    }\n                  });\n\n          if (handlerResultType == null) {\n            throw TypeCheckFailure.makeMergeHandlerTypeNotFunctionError(\n                fieldName, constructorType, handlerType);\n          } else if (resultType == null) {\n            resultType = handlerResultType;\n          } else {\n            // We check that the handler result type is the same as previous result types.\n            if (!handlerResultType.equivalent(resultType)) {\n              throw TypeCheckFailure.makeMergeHandlerTypeMismatchError(\n                  resultType, handlerResultType);\n            }\n          }\n        }\n      }\n    }\n\n    if (handlerTypeMap.isEmpty()) {\n      return resultType;\n    } else {\n      throw TypeCheckFailure.makeMergeHandlerUnusedError(handlerTypeMap.keySet().iterator().next());\n    }\n  }\n\n  private static final Entry<String, Expr>[] prefer(\n      List<Entry<String, Expr>> base, List<Entry<String, Expr>> updates) {\n    Map<String, Expr> updateMap = new LinkedHashMap<>();\n\n    for (Entry<String, Expr> field : updates) {\n      updateMap.put(field.getKey(), field.getValue());\n    }\n\n    List<Entry<String, Expr>> result = new ArrayList<>();\n\n    for (Entry<String, Expr> field : base) {\n      String key = field.getKey();\n\n      Expr inUpdates = updateMap.remove(key);\n\n      if (inUpdates == null) {\n        result.add(field);\n      } else {\n        result.add(new SimpleImmutableEntry<>(key, inUpdates));\n      }\n    }\n\n    for (Entry<String, Expr> field : updateMap.entrySet()) {\n      result.add(field);\n    }\n\n    Entry<String, Expr>[] resultArray = result.toArray(new Entry[result.size()]);\n\n    Arrays.sort(resultArray, entryComparator);\n\n    return resultArray;\n  }\n\n  /** Java 8 introduce {@code comparingByKey}, but we can roll our own pretty easily. */\n  private static final Comparator<Entry<String, Expr>> entryComparator =\n      new Comparator<Entry<String, Expr>>() {\n        public int compare(Entry<String, Expr> a, Entry<String, Expr> b) {\n          return a.getKey().compareTo(b.getKey());\n        }\n      };\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/TypeCheckApplication.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.ExternalVisitor;\n\nfinal class TypeCheckApplication extends ExternalVisitor.Constant<Expr> {\n  private final Expr arg;\n  private final Expr argType;\n  private final TypeCheck typeCheck;\n\n  TypeCheckApplication(Expr arg, Expr argType, TypeCheck typeCheck) {\n    super(null);\n    this.arg = arg;\n    this.argType = argType;\n    this.typeCheck = typeCheck;\n  }\n\n  @Override\n  public Expr onBuiltIn(String name) {\n    if (name.equals(\"Some\")) {\n      if (TypeCheck.isType(this.argType.accept(this.typeCheck))) {\n        return Expr.makeApplication(Expr.Constants.OPTIONAL, this.argType);\n      } else {\n        throw TypeCheckFailure.makeSomeApplicationError(this.arg, this.argType);\n      }\n    }\n    throw TypeCheckFailure.makeBuiltInApplicationError(name, this.arg, this.argType);\n  }\n\n  @Override\n  public Expr onPi(String name, Expr input, Expr result) {\n    if (input.equivalent(this.argType)) {\n      return result.substitute(name, arg).normalize();\n    } else {\n      throw TypeCheckFailure.makeApplicationTypeError(input, this.argType);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/TypeCheckFailure.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport org.dhallj.core.DhallException;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\n\npublic final class TypeCheckFailure extends DhallException {\n  @Override\n  public Throwable fillInStackTrace() {\n    // This is a failure type; stack traces aren't useful.\n    return this;\n  }\n\n  TypeCheckFailure(String message) {\n    super(message);\n  }\n\n  static final TypeCheckFailure makeSortError() {\n    return new TypeCheckFailure(\"Sort has no type, kind, or sort\");\n  }\n\n  static final TypeCheckFailure makeUnboundVariableError(String name) {\n    return new TypeCheckFailure(\"Unbound variable: \" + name);\n  }\n\n  static final TypeCheckFailure makeOperatorError(Operator operator) {\n    String message;\n\n    if (operator == Operator.OR\n        || operator == Operator.AND\n        || operator == Operator.EQUALS\n        || operator == Operator.NOT_EQUALS) {\n      message = operator.toString() + \" only works on Bools\";\n    } else if (operator == Operator.PLUS || operator == Operator.TIMES) {\n      message = operator.toString() + \" only works on Naturals\";\n    } else if (operator == Operator.TEXT_APPEND) {\n      message = operator.toString() + \" only works on Text\";\n    } else if (operator == Operator.LIST_APPEND) {\n      message = operator.toString() + \" only works on Lists\";\n    } else if (operator == Operator.COMBINE || operator == Operator.PREFER) {\n      message = \"You can only combine records\";\n    } else if (operator == Operator.COMBINE_TYPES) {\n      message = operator.toString() + \" requires arguments that are record types\";\n    } else if (operator == Operator.EQUIVALENT) {\n      message = \"Incomparable expression\";\n    } else {\n      message = \"Operator error on \" + operator.toString();\n    }\n\n    return new TypeCheckFailure(message);\n  }\n\n  static final TypeCheckFailure makeListAppendError(Expr lhs, Expr rhs) {\n    return new TypeCheckFailure(\"You can only append Lists with matching element types\");\n  }\n\n  static final TypeCheckFailure makeEquivalenceError(Expr lhs, Expr rhs) {\n    return new TypeCheckFailure(\"You can only append Lists with matching element types\");\n  }\n\n  static final TypeCheckFailure makeInterpolationError(Expr interpolated, Expr interpolatedType) {\n    return new TypeCheckFailure(\"You can only interpolate Text\");\n  }\n\n  static final TypeCheckFailure makeSomeApplicationError(Expr arg, Expr argType) {\n    return new TypeCheckFailure(\"Some argument has the wrong type\");\n  }\n\n  static final TypeCheckFailure makeBuiltInApplicationError(String name, Expr arg, Expr argType) {\n    return new TypeCheckFailure(\"Can't apply \" + name);\n  }\n\n  static final TypeCheckFailure makeApplicationTypeError(Expr expected, Expr received) {\n    return new TypeCheckFailure(\"Wrong type of function argument\");\n  }\n\n  static final TypeCheckFailure makeApplicationError(Expr base, Expr arg) {\n    return new TypeCheckFailure(\"Not a function\");\n  }\n\n  static final TypeCheckFailure makeUnresolvedImportError() {\n    return new TypeCheckFailure(\"Can't type-check unresolved import\");\n  }\n\n  static final TypeCheckFailure makeIfPredicateError(Expr type) {\n    return new TypeCheckFailure(\"Invalid predicate for if\");\n  }\n\n  static final TypeCheckFailure makeIfBranchTypeMismatchError(Expr thenType, Expr elseType) {\n    return new TypeCheckFailure(\"if branches must have matching types\");\n  }\n\n  static final TypeCheckFailure makeLambdaInputError(Expr type) {\n    return new TypeCheckFailure(\"Invalid function input\");\n  }\n\n  static final TypeCheckFailure makePiInputError(Expr type) {\n    return new TypeCheckFailure(\"Invalid function input\");\n  }\n\n  static final TypeCheckFailure makePiOutputError(Expr type) {\n    return new TypeCheckFailure(\"Invalid function output\");\n  }\n\n  static final TypeCheckFailure makeAssertError(Expr type) {\n    return new TypeCheckFailure(\"Not an equivalence\");\n  }\n\n  static final TypeCheckFailure makeFieldAccessError() {\n    return new TypeCheckFailure(\"Not a record or union\");\n  }\n\n  static final TypeCheckFailure makeFieldAccessRecordMissingError(String fieldName) {\n    return new TypeCheckFailure(\"Missing record field: \" + fieldName);\n  }\n\n  static final TypeCheckFailure makeFieldAccessUnionMissingError(String fieldName) {\n    return new TypeCheckFailure(\"Missing constructor: \" + fieldName);\n  }\n\n  static final TypeCheckFailure makeProjectionError() {\n    return new TypeCheckFailure(\"Not a record\");\n  }\n\n  static final TypeCheckFailure makeFieldTypeError(String fieldName, Expr type) {\n    return new TypeCheckFailure(\"Invalid field type\");\n  }\n\n  static final TypeCheckFailure makeFieldDuplicateError(String fieldName) {\n    return new TypeCheckFailure(\"duplicate field: \" + fieldName);\n  }\n\n  static final TypeCheckFailure makeListTypeMismatchError(Expr type1, Expr type2) {\n    return new TypeCheckFailure(\"List elements should all have the same type\");\n  }\n\n  static final TypeCheckFailure makeListTypeError(Expr type) {\n    return new TypeCheckFailure(\"Invalid type for List\");\n  }\n\n  static final TypeCheckFailure makeAnnotationError(Expr expected, Expr received) {\n    return new TypeCheckFailure(\"Expression doesn't match annotation\");\n  }\n\n  static final TypeCheckFailure makeAlternativeTypeError(String fieldName, Expr type) {\n    return new TypeCheckFailure(\"Invalid alternative type\");\n  }\n\n  /** Not sure under what conditions this wouldn't be caught by the parser. */\n  static final TypeCheckFailure makeAlternativeDuplicateError(String fieldName) {\n    return new TypeCheckFailure(\"duplicate field: \" + fieldName);\n  }\n\n  static final TypeCheckFailure makeMergeHandlersTypeError(Expr type) {\n    return new TypeCheckFailure(\"merge expects a record of handlers\");\n  }\n\n  static final TypeCheckFailure makeMergeUnionTypeError(Expr type) {\n    return new TypeCheckFailure(\"toMap expects a union or an Optional\");\n  }\n\n  static final TypeCheckFailure makeMergeHandlerMissingError(String fieldName) {\n    return new TypeCheckFailure(\"Missing handler: \" + fieldName);\n  }\n\n  static final TypeCheckFailure makeMergeHandlerUnusedError(String fieldName) {\n    return new TypeCheckFailure(\"Unused handler: \" + fieldName);\n  }\n\n  static final TypeCheckFailure makeMergeHandlerTypeInvalidError(Expr expected, Expr type) {\n    return new TypeCheckFailure(\"Wrong handler input type\");\n  }\n\n  static final TypeCheckFailure makeMergeHandlerTypeNotFunctionError(\n      String fieldName, Expr expected, Expr type) {\n    return new TypeCheckFailure(\"Handler for \" + fieldName + \" is not a function\");\n  }\n\n  static final TypeCheckFailure makeMergeHandlerTypeMismatchError(Expr type1, Expr type2) {\n    return new TypeCheckFailure(\"Handlers should have the same output type\");\n  }\n\n  static final TypeCheckFailure makeMergeHandlerTypeDisallowedError(Expr type) {\n    return new TypeCheckFailure(\"Disallowed handler type\");\n  }\n\n  static final TypeCheckFailure makeMergeInvalidAnnotationError(Expr expected, Expr inferred) {\n    return new TypeCheckFailure(\"Expression doesn't match annotation\");\n  }\n\n  static final TypeCheckFailure makeToMapTypeError(Expr type) {\n    return new TypeCheckFailure(\"toMap expects a record value\");\n  }\n\n  static final TypeCheckFailure makeToMapRecordKindError(Expr type) {\n    return new TypeCheckFailure(\"toMap expects a record of kind Type\");\n  }\n\n  static final TypeCheckFailure makeToMapRecordTypeMismatchError(Expr type1, Expr type2) {\n    return new TypeCheckFailure(\"toMap expects a homogenous record\");\n  }\n\n  static final TypeCheckFailure makeToMapResultTypeMismatchError(Expr expected, Expr inferred) {\n    return new TypeCheckFailure(\"toMap result type doesn't match annotation\");\n  }\n\n  static final TypeCheckFailure makeToMapMissingAnnotationError() {\n    return new TypeCheckFailure(\"An empty toMap requires a type annotation\");\n  }\n\n  static final TypeCheckFailure makeToMapInvalidAnnotationError(Expr type) {\n    return new TypeCheckFailure(\"An empty toMap was annotated with an invalid type\");\n  }\n\n  static final TypeCheckFailure makeWithTypeError(Expr type) {\n    return new TypeCheckFailure(\"with only works on records\");\n  }\n}\n"
  },
  {
    "path": "modules/core/src/main/java/org/dhallj/core/typechecking/Universe.java",
    "content": "package org.dhallj.core.typechecking;\n\nimport org.dhallj.core.Expr;\n\npublic enum Universe {\n  TYPE,\n  KIND,\n  SORT;\n\n  public final Universe max(Universe other) {\n    if (this == SORT || other == SORT) {\n      return SORT;\n    } else if (this == KIND || other == KIND) {\n      return KIND;\n    } else {\n      return TYPE;\n    }\n  }\n\n  public final Expr toExpr() {\n    if (this == TYPE) {\n      return Expr.Constants.TYPE;\n    } else if (this == KIND) {\n      return Expr.Constants.KIND;\n    } else {\n      return Expr.Constants.SORT;\n    }\n  }\n\n  public static final boolean isUniverse(Expr expr) {\n    return fromExpr(expr) != null;\n  }\n\n  public static final Universe fromExpr(Expr expr) {\n    String name = Expr.Util.asBuiltIn(expr);\n\n    if (name != null) {\n      if (name.equals(\"Type\")) {\n        return TYPE;\n      } else if (name.equals(\"Kind\")) {\n        return KIND;\n      } else if (name.equals(\"Sort\")) {\n        return SORT;\n      }\n    }\n    return null;\n  }\n\n  public static Universe functionCheck(Universe input, Universe output) {\n    if (input == null || output == null) {\n      return null;\n    }\n\n    if (output == Universe.TYPE) {\n      return Universe.TYPE;\n    } else {\n      return input.max(output);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/core/src/test/java/org/dhallj/cbor/CborSuite.scala",
    "content": "package org.dhallj.cbor\n\nimport co.nstant.in.cbor.{CborBuilder, CborEncoder}\nimport java.io.ByteArrayOutputStream\nimport java.math.BigInteger\nimport munit.ScalaCheckSuite\nimport org.scalacheck.Prop\n\nclass CborSuite extends ScalaCheckSuite {\n  def roundTripDouble(value: Double): Option[Double] = {\n    val writer = new Writer.ByteArrayWriter()\n    writer.writeDouble(value)\n\n    val bytes = writer.getBytes\n    val reader = new Reader.ByteArrayReader(bytes)\n    reader.nextSymbol(DoubleValueVisitor)\n  }\n\n  def encodeDoubleWithCborJava(value: Double): Array[Byte] = {\n    val stream = new ByteArrayOutputStream()\n    new CborEncoder(stream).encode(new CborBuilder().add(value).build())\n\n    return stream.toByteArray\n  }\n\n  property(\"Writer and Reader should round-trip doubles\") {\n    Prop.forAll((value: Double) => roundTripDouble(value) == Some(value))\n  }\n\n  property(\"Writer should agree with cbor-java\") {\n    Prop.forAll { (value: Double) =>\n      val writer = new Writer.ByteArrayWriter()\n      writer.writeDouble(value)\n\n      writer.getBytes.sameElements(encodeDoubleWithCborJava(value))\n    }\n  }\n\n  test(\"Writer and Reader should round-trip special-case doubles\") {\n    assertEquals(roundTripDouble(0.0), Some(0.0))\n    assertEquals(roundTripDouble(-0.0), Some(-0.0))\n    assertEquals(roundTripDouble(Double.PositiveInfinity), Some(Double.PositiveInfinity))\n    assertEquals(roundTripDouble(Double.NegativeInfinity), Some(Double.NegativeInfinity))\n    assert(roundTripDouble(Double.NaN).exists(_.isNaN))\n  }\n\n  object DoubleValueVisitor extends Visitor[Option[Double]] {\n    def onUnsignedInteger(value: BigInteger): Option[Double] = None\n    def onNegativeInteger(value: BigInteger): Option[Double] = None\n    def onByteString(value: Array[Byte]): Option[Double] = None\n    def onTextString(value: String): Option[Double] = None\n    def onVariableArray(length: BigInteger, name: String): Option[Double] = None\n    def onArray(length: BigInteger, tagI: BigInteger): Option[Double] = None\n    def onMap(size: BigInteger): Option[Double] = None\n    def onFalse: Option[Double] = None\n    def onTrue: Option[Double] = None\n    def onNull: Option[Double] = None\n    def onHalfFloat(value: Float): Option[Double] = Some(value.toDouble)\n    def onSingleFloat(value: Float): Option[Double] = Some(value.toDouble)\n    def onDoubleFloat(value: Double): Option[Double] = Some(value)\n    def onTag: Option[Double] = None\n  }\n}\n"
  },
  {
    "path": "modules/core/src/test/java/org/dhallj/cbor/HalfFloatSuite.scala",
    "content": "package org.dhallj.cbor\n\nimport munit.FunSuite\nimport org.scalacheck.Prop\n\nclass HalfFloatSuite extends FunSuite {\n  def roundTripInt(x: Int): Int =\n    HalfFloat.toFloat(HalfFloat.fromFloat(x.toFloat)).toInt\n\n  test(\"HalfFloat conversions round-trip integers with abs <= 2048\") {\n    0.to(2048).foreach { x =>\n      assertEquals(roundTripInt(x), x)\n      assertEquals(roundTripInt(-x), -x)\n    }\n  }\n\n  test(\"HalfFloat conversions round-trip even integers with abs <= 4096\") {\n    1.to(1024).foreach { x =>\n      assertEquals(roundTripInt((x * 2) + 2048), (x * 2) + 2048)\n      assertEquals(roundTripInt(-((x * 2) + 2048)), -((x * 2) + 2048))\n      assertEquals(roundTripInt((x * 2) + 2048 - 1), (x * 2) + 2048)\n      assertEquals(roundTripInt(-((x * 2) + 2048 - 1)), -((x * 2) + 2048))\n    }\n  }\n\n  test(\"HalfFloat conversions round-trip through float for all values\") {\n    0.until(1 << 16).foreach { x =>\n      val asFloat = HalfFloat.toFloat(x)\n\n      if (!asFloat.isNaN) {\n        assertEquals(HalfFloat.fromFloat(asFloat), x)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "modules/imports/README.md",
    "content": "# Imports\n\nA reference implementation of import resolution using [Cats Effect](https://typelevel.org/cats-effect/)."
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/Canonicalization.scala",
    "content": "package org.dhallj.imports\n\nimport java.nio.file.{Path, Paths}\n\nimport cats.{ApplicativeError, MonadError}\nimport cats.implicits._\nimport cats.effect.Sync\nimport org.dhallj.core.DhallException.ResolutionFailure\nimport org.dhallj.imports.ImportContext._\n\nimport scala.collection.JavaConverters._\n\nobject Canonicalization {\n\n  def canonicalize[F[_]](imp: ImportContext)(implicit F: ApplicativeError[F, Throwable]): F[ImportContext] = imp match {\n    case Remote(uri, headers) => F.pure(Remote(uri.normalize, headers))\n    case Local(path)          => LocalFile[F](path).map(_.canonicalize.toPath).map(Local)\n    case Classpath(path)      => LocalFile[F](path).map(_.canonicalize.toPath).map(Classpath)\n    case i                    => F.pure(i)\n  }\n\n  def canonicalize[F[_]](parent: ImportContext, child: ImportContext)(implicit\n    F: MonadError[F, Throwable]\n  ): F[ImportContext] =\n    parent match {\n      case Remote(uri, headers) =>\n        child match {\n          //A transitive relative import is parsed as local but is resolved as a remote import\n          // eg https://github.com/dhall-lang/dhall-lang/blob/master/Prelude/Integer/add has a local import but we still\n          //need to resolve this as a remote import\n          //Also note that if the path is absolute then this violates referential sanity but we handle that elsewhere\n          case Local(path) =>\n            if (path.isAbsolute) canonicalize[F](child)\n            else canonicalize[F](Remote(uri.resolve(path.toString), headers))\n          case _ => canonicalize[F](child)\n        }\n      case Local(path) =>\n        child match {\n          case Local(path2) =>\n            for {\n              parent <- LocalFile[F](path)\n              c <- LocalFile[F](path2)\n            } yield Local(parent.chain(c).canonicalize.toPath)\n          case _ => canonicalize[F](child)\n        }\n      //TODO - determine semantics of classpath imports\n      case Classpath(path) =>\n        child match {\n          //Also note that if the path is absolute then this violates referential sanity but we handle that elsewhere\n          case Local(path2) =>\n            for {\n              parent <- LocalFile[F](path)\n              c <- LocalFile[F](path2)\n            } yield Classpath(parent.chain(c).canonicalize.toPath)\n          case _ => canonicalize[F](child)\n        }\n      case _ => canonicalize[F](child)\n    }\n\n  private case class LocalFile(dirs: LocalDirs, filename: String) {\n    def toPath: Path = {\n      def toPath(l: List[String]) = \"/\" + l.intercalate(\"/\")\n\n      val s: String = dirs.ds match {\n        case Nil => \"\"\n        case l @ (h :: t) =>\n          h match {\n            case h if h == \".\" || h == \"..\" || h == \"~\" => s\"$h${toPath(t)}\"\n            case _                                      => toPath(l)\n          }\n      }\n      Paths.get(s\"$s/$filename\")\n    }\n\n    def chain(other: LocalFile): LocalFile = LocalFile.chain(this, other)\n\n    def canonicalize: LocalFile = LocalFile.canonicalize(this)\n  }\n\n  private object LocalFile {\n    def apply[F[_]](path: Path)(implicit F: ApplicativeError[F, Throwable]): F[LocalFile] =\n      path.iterator().asScala.toList.map(_.toString) match {\n        case Nil => F.raiseError(new ResolutionFailure(\"This shouldn't happen - / can't import a dhall expression\"))\n        case l   => F.pure(LocalFile(LocalDirs(l.take(l.length - 1)), l.last))\n      }\n\n    def canonicalize(f: LocalFile): LocalFile =\n      LocalFile(f.dirs.canonicalize, f.filename.stripPrefix(\"\\\"\").stripSuffix(\"\\\"\"))\n\n    def chain(lhs: LocalFile, rhs: LocalFile): LocalFile = LocalFile(LocalDirs.chain(lhs.dirs, rhs.dirs), rhs.filename)\n  }\n\n  private case class LocalDirs(ds: List[String]) {\n    def isRelative: Boolean = ds.nonEmpty && (ds.head == \".\" || ds.head == \"..\")\n\n    def canonicalize: LocalDirs = LocalDirs.canonicalize(this)\n\n    def chain(other: LocalDirs): LocalDirs = LocalDirs.chain(this, other)\n  }\n\n  private object LocalDirs {\n    def chain(lhs: LocalDirs, rhs: LocalDirs): LocalDirs = if (rhs.isRelative) LocalDirs(lhs.ds ++ rhs.ds) else rhs\n\n    def canonicalize(d: LocalDirs): LocalDirs = d.ds match {\n      case Nil => d\n      case l   => LocalDirs(canonicalize(l.map(_.stripPrefix(\"\\\"\").stripSuffix(\"\\\"\"))))\n    }\n\n    def canonicalize(l: List[String]): List[String] =\n      l.tail\n        .foldLeft(List(l.head)) { (acc, next) =>\n          next match {\n            case \".\"  => acc\n            case \"..\" => acc.tail\n            case o    => o :: acc\n          }\n        }\n        .reverse\n\n  }\n\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/CorsComplianceCheck.scala",
    "content": "package org.dhallj.imports\n\nimport java.net.URI\n\nimport cats.effect.Sync\nimport org.dhallj.core.DhallException.ResolutionFailure\nimport org.http4s.Headers\nimport org.typelevel.ci.CIString\n\nobject CorsComplianceCheck {\n\n  def apply[F[_]](parent: ImportContext, child: ImportContext, headers: Headers)(implicit F: Sync[F]): F[Unit] =\n    parent match {\n      case ImportContext.Remote(uri, _) =>\n        child match {\n          case ImportContext.Remote(uri2, _) =>\n            if (sameOrigin(uri, uri2))\n              F.unit\n            else\n              headers\n                .get(CIString(\"Access-Control-Allow-Origin\"))\n                .fold(\n                  F.raiseError[Unit](\n                    new ResolutionFailure(\n                      s\"CORS compliance failure - No Access-Control-Allow-Origin header for import $uri2 from $uri\"\n                    )\n                  )\n                ) { h =>\n                  if (h.head.value.trim == \"*\" || sameOrigin(new URI(h.head.value), uri))\n                    F.unit\n                  else\n                    F.raiseError(\n                      new ResolutionFailure(\n                        s\"CORS compliance failure - ${h.head.value.trim} is invalid for import $uri2 from $uri\"\n                      )\n                    )\n                }\n          case _ => F.unit\n        }\n      case _ => F.unit\n    }\n\n  private def sameOrigin(uri: URI, uri2: URI): Boolean =\n    uri.getScheme == uri2.getScheme && uri.getAuthority == uri2.getAuthority && uri.getPort == uri2.getPort\n\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/ImportCache.scala",
    "content": "package org.dhallj.imports\n\nimport cats.Applicative\nimport cats.effect.Async\nimport cats.implicits._\nimport java.nio.file.{Files, Path, Paths}\nimport org.dhallj.core.DhallException.ResolutionFailure\n\ntrait ImportCache[F[_]] {\n  def get(key: Array[Byte]): F[Option[Array[Byte]]]\n\n  def put(key: Array[Byte], value: Array[Byte]): F[Unit]\n}\n\nobject ImportCache {\n\n  /*\n   * Improves the ergonomics when resolving imports if we don't have to check\n   * if the cache exists. So if we fail to construct an imports cache,\n   * we warn and return this instead.\n   */\n  class NoopImportCache[F[_]](implicit F: Applicative[F]) extends ImportCache[F] {\n    override def get(key: Array[Byte]): F[Option[Array[Byte]]] = F.pure(None)\n\n    override def put(key: Array[Byte], value: Array[Byte]): F[Unit] = F.unit\n  }\n\n  private class Impl[F[_]](rootDir: Path)(implicit F: Async[F]) extends ImportCache[F] {\n    override def get(key: Array[Byte]): F[Option[Array[Byte]]] = {\n      val p = path(key)\n      if (Files.exists(p)) {\n        F.delay(Some(Files.readAllBytes(p)))\n      } else {\n        F.pure(None)\n      }\n    }\n\n    override def put(key: Array[Byte], value: Array[Byte]): F[Unit] =\n      F.delay(Files.write(path(key), value))\n\n    private def path(key: Array[Byte]): Path = rootDir.resolve(s\"1220${toHex(key)}\")\n\n    private def toHex(bs: Array[Byte]): String = {\n      val sb = new StringBuilder\n      for (b <- bs) {\n        sb.append(String.format(\"%02x\", Byte.box(b)))\n      }\n      sb.toString\n    }\n  }\n\n  def apply[F[_] <: AnyRef](rootDir: Path)(implicit F: Async[F]): F[Option[ImportCache[F]]] =\n    for {\n      _ <- if (!Files.exists(rootDir)) F.delay(Files.createDirectories(rootDir)).void else F.unit\n      perms <- F.delay(Files.isReadable(rootDir) && Files.isWritable(rootDir))\n    } yield (if (perms) Some(new Impl[F](rootDir)) else None)\n\n  def apply[F[_] <: AnyRef](cacheName: String)(implicit F: Async[F]): F[ImportCache[F]] = {\n    def makeCacheFromEnvVar(env: String, relativePath: String): F[Option[ImportCache[F]]] =\n      for {\n        envValO <- F.delay(sys.env.get(env))\n        cache <- envValO.fold(F.pure(Option.empty[ImportCache[F]]))(envVal =>\n          for {\n            rootDir <- F.pure(Paths.get(envVal, relativePath, cacheName))\n            c <- apply(rootDir)\n          } yield c\n        )\n      } yield cache\n\n    def backupCache =\n      for {\n        cacheO <-\n          if (isWindows)\n            makeCacheFromEnvVar(\"LOCALAPPDATA\", \"\")\n          else makeCacheFromEnvVar(\"HOME\", \".cache\")\n        cache <- F.fromOption(cacheO, new ResolutionFailure(\"Failed to create cache\"))\n      } yield cache\n\n    def isWindows = System.getProperty(\"os.name\").toLowerCase.contains(\"windows\")\n\n    for {\n      xdgCache <- makeCacheFromEnvVar(\"XDG_CACHE_HOME\", \"\")\n      cache <- xdgCache.fold(backupCache)(F.pure)\n    } yield cache\n\n  }\n\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/ImportContext.scala",
    "content": "package org.dhallj.imports\n\nimport java.net.URI\nimport java.nio.file.Path\nimport org.dhallj.core.Expr\n\nsealed abstract class ImportContext extends Product with Serializable\n\nobject ImportContext {\n  case object Missing extends ImportContext\n  case class Env(value: String) extends ImportContext\n  case class Local(absolutePath: Path) extends ImportContext\n  case class Classpath(absolutePath: Path) extends ImportContext\n  case class Remote(url: URI, using: Expr) extends ImportContext\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/ReferentialSanityCheck.scala",
    "content": "package org.dhallj.imports\n\nimport cats.effect.Sync\nimport org.dhallj.core.DhallException.ResolutionFailure\n\nobject ReferentialSanityCheck {\n\n  def apply[F[_]](parent: ImportContext, child: ImportContext)(implicit F: Sync[F]): F[Unit] = parent match {\n    case ImportContext.Remote(uri, _) =>\n      child match {\n        case ImportContext.Remote(_, _) => F.unit\n        case ImportContext.Missing      => F.unit\n        case ImportContext.Local(path) =>\n          F.raiseError(\n            new ResolutionFailure(\n              s\"Referential sanity violation - remote import $uri cannot reference local import $path\"\n            )\n          )\n        case ImportContext.Classpath(path) =>\n          F.raiseError(\n            new ResolutionFailure(\n              s\"Referential sanity violation - remote import $uri cannot reference classpath import $path\"\n            )\n          )\n        case ImportContext.Env(v) =>\n          F.raiseError(\n            new ResolutionFailure(s\"Referential sanity violation - remote import $uri cannot reference env import $v\")\n          )\n      }\n    case ImportContext.Missing => F.raiseError(new ResolutionFailure(s\"Missing import cannot reference import $child\"))\n    case _                     => F.unit\n  }\n\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/ResolveImports.scala",
    "content": "package org.dhallj.imports\n\nimport java.nio.file.{Path, Paths}\n\nimport cats.effect.Async\nimport org.dhallj.core.Expr\nimport org.http4s.client.Client\n\nobject Resolver {\n  def resolve[F[_] <: AnyRef](expr: Expr)(implicit Client: Client[F], F: Async[F]): F[Expr] =\n    resolveRelativeTo[F](cwd)(expr)\n\n  def resolveRelativeTo[F[_] <: AnyRef](relativeTo: Path)(\n    expr: Expr\n  )(implicit Client: Client[F], F: Async[F]): F[Expr] =\n    F.flatMap(ResolveImportsVisitor[F](relativeTo))(expr.accept(_))\n\n  def resolve[F[_] <: AnyRef](\n    semanticCache: ImportCache[F],\n    semiSemanticCache: ImportCache[F]\n  )(expr: Expr)(implicit Client: Client[F], F: Async[F]): F[Expr] =\n    resolveRelativeTo[F](semanticCache, semiSemanticCache)(cwd)(expr)\n\n  def resolveRelativeTo[F[_] <: AnyRef](\n    semanticCache: ImportCache[F],\n    semiSemanticCache: ImportCache[F]\n  )(relativeTo: Path)(expr: Expr)(implicit Client: Client[F], F: Async[F]): F[Expr] =\n    expr.accept(ResolveImportsVisitor[F](semanticCache, semiSemanticCache, relativeTo))\n\n  def resolve[F[_] <: AnyRef](\n    semanticCache: ImportCache[F]\n  )(expr: Expr)(implicit Client: Client[F], F: Async[F]): F[Expr] =\n    resolveRelativeTo[F](semanticCache)(cwd)(expr)\n\n  def resolveRelativeTo[F[_] <: AnyRef](\n    semanticCache: ImportCache[F]\n  )(relativeTo: Path)(expr: Expr)(implicit Client: Client[F], F: Async[F]): F[Expr] =\n    expr.accept(ResolveImportsVisitor[F](semanticCache, new ImportCache.NoopImportCache[F], relativeTo))\n\n  private def cwd: Path = Paths.get(\".\")\n\n  final class Ops(val expr: Expr) extends AnyVal {\n    def resolveImports[F[_] <: AnyRef](implicit Client: Client[F], F: Async[F]): F[Expr] =\n      resolve[F](expr)\n\n    def resolveImportsRelativeTo[F[_] <: AnyRef](relativeTo: Path)(implicit Client: Client[F], F: Async[F]): F[Expr] =\n      resolveRelativeTo[F](relativeTo)(expr)\n  }\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/ResolveImportsVisitor.scala",
    "content": "package org.dhallj.imports\n\nimport java.net.URI\nimport java.nio.file.{Files, Path, Paths}\nimport java.security.MessageDigest\n\nimport cats.Apply\nimport cats.data.NonEmptyList\nimport cats.effect.{Async, Concurrent}\nimport cats.implicits._\nimport org.dhallj.cats.LiftVisitor\nimport org.dhallj.core.DhallException.ResolutionFailure\nimport org.dhallj.core.Expr.ImportMode\nimport org.dhallj.core.Expr.Util.typeCheck\nimport org.dhallj.core._\nimport org.dhallj.core.binary.Decode\nimport org.dhallj.imports.Canonicalization.canonicalize\nimport org.dhallj.imports.ImportContext.Local\nimport org.dhallj.parser.DhallParser\nimport org.http4s.Status.Successful\nimport org.http4s.Uri.unsafeFromString\nimport org.http4s.client.Client\nimport org.http4s.{EntityDecoder, Request}\n\nimport scala.collection.mutable.{Map => MMap}\n\n//TODO proper error handling\nfinal private class ResolveImportsVisitor[F[_] <: AnyRef](\n  semanticCache: ImportCache[F],\n  semiSemanticCache: ImportCache[F],\n  parents: NonEmptyList[ImportContext]\n)(implicit\n  Client: Client[F],\n  F: Async[F]\n) extends LiftVisitor[F](F, true) {\n  def this(\n    semanticCache: ImportCache[F],\n    semiSemanticCache: ImportCache[F],\n    parents: List[ImportContext]\n  )(implicit Client: Client[F], F: Async[F]) = {\n    this(semanticCache, semiSemanticCache, NonEmptyList.fromListUnsafe(parents))\n  }\n\n  private var duplicateImportCache: MMap[(ImportContext, ImportMode), Expr] = MMap.empty\n\n  override def onOperatorApplication(operator: Operator, lhs: F[Expr], rhs: F[Expr]): F[Expr] =\n    if (operator == Operator.IMPORT_ALT)\n      lhs.handleErrorWith {\n        case e: ResolutionFailure if e.isAbsentImport => rhs\n        case other                                    => F.raiseError(other)\n      }\n    else {\n      F.map2(lhs, rhs)(Expr.makeOperatorApplication(operator, _, _))\n    }\n\n  override def onLocalImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    onImport(ImportContext.Local(path), mode, hash)\n\n  override def onClasspathImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    onImport(ImportContext.Classpath(path), mode, hash)\n\n  override def onRemoteImport(url: URI, using: F[Expr], mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    if (using.ne(null)) using >>= (u => onImport(ImportContext.Remote(url, u), mode, hash))\n    else onImport(ImportContext.Remote(url, null), mode, hash)\n\n  override def onEnvImport(value: String, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    onImport(ImportContext.Env(value), mode, hash)\n\n  override def onMissingImport(mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] =\n    onImport(ImportContext.Missing, mode, hash)\n\n  private[this] def checkHash(encoded: Array[Byte], expected: Array[Byte]): Boolean = {\n    val hashed = MessageDigest.getInstance(\"SHA-256\").digest(encoded)\n    hashed.sameElements(expected)\n  }\n\n  private def onImport(i: ImportContext, mode: Expr.ImportMode, hash: Array[Byte]): F[Expr] = {\n    //TODO check that equality is sensibly defined for URI and Path\n    def rejectCyclicImports(imp: ImportContext, parents: NonEmptyList[ImportContext]): F[Unit] =\n      if (parents.exists(_ == imp))\n        F.raiseError[Unit](new ResolutionFailure(s\"Cyclic import - $imp is already imported in chain $parents\"))\n      else F.unit\n\n    def importLocation(imp: ImportContext): F[Expr] =\n      imp match {\n        case ImportContext.Local(path) => makeLocation(\"Local\", path.toString)\n        // Cannot support this and remain spec-compliant as result type must be <Local Text | Remote Text | Environment Text | Missing>\n        case ImportContext.Classpath(path) =>\n          F.raiseError(new ResolutionFailure(\"Importing classpath as location is not supported\"))\n        case ImportContext.Remote(uri, _) => makeLocation(\"Remote\", uri.toString)\n        case ImportContext.Env(value)     => makeLocation(\"Environment\", value)\n        case ImportContext.Missing        => F.pure(Expr.makeFieldAccess(Expr.Constants.LOCATION_TYPE, \"Missing\"))\n      }\n\n    def makeLocation(field: String, value: String): F[Expr] =\n      F.pure(\n        Expr.makeApplication(Expr.makeFieldAccess(Expr.Constants.LOCATION_TYPE, field), Expr.makeTextLiteral(value))\n      )\n\n    def checkHashesMatch(encoded: Array[Byte], expected: Array[Byte]): F[Unit] = {\n      if (checkHash(encoded, expected)) F.unit\n      else F.raiseError(new ResolutionFailure(\"Cached expression does not match its hash\"))\n    }\n\n    def loadWithSemanticCache(imp: ImportContext, mode: ImportMode, hash: Array[Byte]): F[Expr] =\n      if (hash == null) loadWithSemiSemanticCache(imp, mode, hash)\n      else\n        for {\n          cached <- semanticCache.get(hash)\n          e <- cached match {\n            case Some(bs) if checkHash(bs, hash) =>\n              F.delay(Decode.decode(bs))\n            case _ =>\n              for {\n                e <- loadWithSemiSemanticCache(imp, mode, hash)\n                n = e.normalize.alphaNormalize\n                bs = n.getEncodedBytes\n                _ <- checkHashesMatch(bs, hash)\n                _ <- semanticCache.put(hash, bs)\n              } yield n\n          }\n        } yield e\n\n    def fetch(imp: ImportContext): F[String] = imp match {\n      case ImportContext.Env(value) =>\n        for {\n          vO <- F.delay(sys.env.get(value))\n          v <- vO.fold(\n            F.raiseError[String](new ResolutionFailure(s\"Missing import - env import $value undefined\", true))\n          )(F.pure)\n        } yield v\n      case ImportContext.Local(path) =>\n        for {\n          v <- {\n            if (Files.exists(path)) {\n              F.delay(new String(Files.readAllBytes(path)))\n            } else {\n              F.raiseError(new ResolutionFailure(s\"Missing import - file $path does not exist\", true))\n            }\n          }\n        } yield v\n      case ImportContext.Classpath(path) =>\n        for {\n          v <-\n            F.delay(getClass.getResourceAsStream(path.toString)).flatMap { stream =>\n              if (stream.ne(null)) {\n                F.delay(scala.io.Source.fromInputStream(stream).mkString)\n              } else {\n                F.raiseError[String](new ResolutionFailure(s\"Missing import - resource $path does not exist\", true))\n              }\n            }\n        } yield v\n      case ImportContext.Remote(uri, using) =>\n        for {\n          headers <- F.fromOption(ToHeaders(`using`), new ResolutionFailure(\"Invalid using clause\"))\n          req <- F.pure(Request[F](uri = unsafeFromString(uri.toString), headers = headers))\n          resp <- Client.fetch[String](req) {\n            case Successful(resp) =>\n              for {\n                s <- EntityDecoder.decodeText[F](resp)\n                _ <- if (parents.nonEmpty) CorsComplianceCheck(parents.head, imp, resp.headers) else F.unit\n              } yield s\n            case _ =>\n              F.raiseError[String](\n                new ResolutionFailure(s\"Missing import - cannot resolve $uri\", true)\n              )\n          }\n        } yield resp\n      case ImportContext.Missing => F.raiseError(new ResolutionFailure(\"Missing import - cannot resolve missing\", true))\n    }\n\n    def loadWithSemiSemanticCache(imp: ImportContext, mode: ImportMode, hash: Array[Byte]): F[Expr] = mode match {\n      case ImportMode.LOCATION => F.raiseError(new ResolutionFailure(\"Unreachable - location imports already handled\"))\n      case ImportMode.RAW_TEXT =>\n        for {\n          text <- fetch(imp)\n        } yield Expr.makeTextLiteral(text)\n      case ImportMode.CODE =>\n        for {\n          text <- fetch(imp)\n          parsed <- F.delay(DhallParser.parse(text))\n          resolved <- {\n            val v = new ResolveImportsVisitor[F](semanticCache, semiSemanticCache, imp :: parents)\n            v.duplicateImportCache = this.duplicateImportCache\n            parsed.accept(v)\n          }\n          semiHash = MessageDigest.getInstance(\"SHA-256\").digest(resolved.getEncodedBytes)\n          cached <- semiSemanticCache.get(semiHash)\n          expr <- cached match {\n            case Some(bs) => F.delay(Decode.decode(bs))\n            case None =>\n              for {\n                _ <- F.delay(typeCheck(resolved))\n                //TODO substitutions here?\n                normalized <- F.delay(resolved.normalize)\n                _ <- semiSemanticCache.put(semiHash, normalized.getEncodedBytes)\n              } yield normalized\n          }\n        } yield expr\n    }\n\n    def resolve(imp: ImportContext, mode: ImportMode, hash: Array[Byte]): F[Expr] = {\n      val p = (imp, mode)\n      if (duplicateImportCache.contains(p)) {\n        val cached = duplicateImportCache.get(p).get\n        if (hash == null) {\n          F.delay(cached)\n        } else {\n          checkHashesMatch(cached.getEncodedBytes, hash).as(cached)\n        }\n      } else {\n        for {\n          e <- loadWithSemanticCache(imp, mode, hash)\n          _ <- F.delay(duplicateImportCache.put(p, e))\n        } yield e\n      }\n    }\n\n    def importNonLocation(imp: ImportContext, mode: ImportMode, hash: Array[Byte]) =\n      for {\n        _ <- ReferentialSanityCheck(parents.head, imp)\n        _ <- rejectCyclicImports(imp, parents)\n        r <- resolve(imp, mode, hash)\n      } yield r\n\n    for {\n      imp <- canonicalize[F](parents.head, i)(F)\n      result <- if (mode == ImportMode.LOCATION) importLocation(imp) else importNonLocation(imp, mode, hash)\n    } yield result\n  }\n}\n\nprivate object ResolveImportsVisitor {\n  def apply[F[_] <: AnyRef: Async: Client](relativeTo: Path): F[ResolveImportsVisitor[F]] =\n    Apply[F].map2(ImportCache[F](\"dhall\"), ImportCache[F](\"dhallj\"))(apply[F](_, _, relativeTo))\n\n  def apply[F[_] <: AnyRef: Async: Client](semanticCache: ImportCache[F],\n                                           semiSemanticCache: ImportCache[F],\n                                           relativeTo: Path\n  ): ResolveImportsVisitor[F] =\n    //We add a placeholder filename \"package.dhall\" for the base directory as a Local import must have a filename\n    new ResolveImportsVisitor[F](semanticCache,\n                                 semiSemanticCache,\n                                 NonEmptyList.one(Local(relativeTo.resolve(\"package.dhall\")))\n    )\n\n  def apply[F[_] <: AnyRef: Async: Client](semanticCache: ImportCache[F], relativeTo: Path): ResolveImportsVisitor[F] =\n    apply[F](semanticCache, new ImportCache.NoopImportCache[F], relativeTo)\n\n  private def cwd: Path = Paths.get(\".\")\n\n  def apply[F[_] <: AnyRef: Async: Client]: F[ResolveImportsVisitor[F]] = apply[F](cwd)\n\n  def apply[F[_] <: AnyRef: Async: Client](semanticCache: ImportCache[F],\n                                           semiSemanticCache: ImportCache[F]\n  ): ResolveImportsVisitor[F] =\n    apply[F](semanticCache, semiSemanticCache, cwd)\n\n  def apply[F[_] <: AnyRef: Async: Client](semanticCache: ImportCache[F]): ResolveImportsVisitor[F] =\n    apply[F](semanticCache, cwd)\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/ToHeaders.scala",
    "content": "package org.dhallj.imports\n\nimport java.util.AbstractMap.SimpleImmutableEntry\nimport java.util.Map.Entry\nimport org.dhallj.core.Expr\nimport org.dhallj.core.Expr.Util.{asListLiteral, asRecordLiteral, asSimpleTextLiteral}\nimport org.dhallj.core.typechecking.TypeCheckFailure\nimport org.http4s.{Header, Headers}\nimport org.typelevel.ci.CIString\n\nimport scala.collection.JavaConverters._\n\nobject ToHeaders {\n  private val validType1: Expr = Expr.makeApplication(\n    Expr.Constants.LIST,\n    Expr.makeRecordType(\n      Array[Entry[String, Expr]](\n        new SimpleImmutableEntry(\"mapKey\", Expr.Constants.TEXT),\n        new SimpleImmutableEntry(\"mapValue\", Expr.Constants.TEXT)\n      )\n    )\n  )\n\n  private val validType2: Expr = Expr.makeApplication(\n    Expr.Constants.LIST,\n    Expr.makeRecordType(\n      Array[Entry[String, Expr]](\n        new SimpleImmutableEntry(\"header\", Expr.Constants.TEXT),\n        new SimpleImmutableEntry(\"value\", Expr.Constants.TEXT)\n      )\n    )\n  )\n\n  private def isValidType(expr: Expr): Boolean = {\n    try {\n      val tpe = Expr.Util.typeCheck(expr)\n\n      tpe == validType1 || tpe == validType2\n    } catch {\n      case _: TypeCheckFailure => false\n    }\n  }\n\n  // See https://discourse.dhall-lang.org/t/valid-expressions-for-using-headers/205\n  // For the moment, this is consistent with the Haskell implementation\n  def apply(expr: Expr): Option[Headers] =\n    if (expr eq null) Some(Headers.empty)\n    else {\n      if (!isValidType(expr)) {\n        None\n      } else {\n        //TODO do we need to .accept(this) on expr?\n        val e = expr.normalize\n        val l = asListLiteral(e)\n        if (l eq null) {\n          Some(Headers.empty)\n        } else {\n          val hs: List[Header.Raw] = l.asScala.toList.flatMap { e =>\n            // e should have type `List { header : Text, value Text }`\n            // or `List { mapKey : Text, mapValue Text }`\n            val r = asRecordLiteral(e)\n            if (r eq null) {\n              None\n            } else {\n              if (r.size == 2) {\n                val map = r.asScala.map(e => e.getKey -> e.getValue).toMap\n                if (map.contains(\"header\") && map.contains(\"value\")) {\n                  val key = asSimpleTextLiteral(map(\"header\"))\n                  val value = asSimpleTextLiteral(map(\"value\"))\n\n                  if ((key ne null) && (value ne null)) {\n                    Some(Header.Raw(CIString(key), value))\n                  } else None\n                } else if (map.contains(\"mapKey\") && map.contains(\"mapValue\")) {\n                  val key = asSimpleTextLiteral(map(\"mapKey\"))\n                  val value = asSimpleTextLiteral(map(\"mapValue\"))\n\n                  if ((key ne null) && (value ne null)) {\n                    Some(Header.Raw(CIString(key), value))\n                  } else None\n                } else None\n              } else None\n            }\n          }\n          Some(Headers(hs))\n        }\n      }\n    }\n}\n"
  },
  {
    "path": "modules/imports/src/main/scala/org/dhallj/imports/syntax/package.scala",
    "content": "package org.dhallj.imports\n\nimport org.dhallj.core.Expr\nimport scala.language.implicitConversions\n\npackage object syntax {\n  implicit def toResolveImportOps(expr: Expr): Resolver.Ops = new Resolver.Ops(expr)\n}\n"
  },
  {
    "path": "modules/imports/src/test/resources/alternate/other.dhall",
    "content": "let x = 2 in x"
  },
  {
    "path": "modules/imports/src/test/resources/alternate/package.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/resources/cache-write/package.dhall",
    "content": "let x = 2 in x"
  },
  {
    "path": "modules/imports/src/test/resources/cyclic/other.dhall",
    "content": "let x = /cyclic/package.dhall in x"
  },
  {
    "path": "modules/imports/src/test/resources/cyclic/package.dhall",
    "content": "let x = ./other.dhall in x"
  },
  {
    "path": "modules/imports/src/test/resources/cyclic-relative-paths/other.dhall",
    "content": "let x = ./package.dhall in x"
  },
  {
    "path": "modules/imports/src/test/resources/cyclic-relative-paths/package.dhall",
    "content": "let x = ./other.dhall in x"
  },
  {
    "path": "modules/imports/src/test/resources/hashed/package.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/resources/local/package.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/resources/local-local-absolute/package.dhall",
    "content": "let x = /local-local-absolute-2/package.dhall in x"
  },
  {
    "path": "modules/imports/src/test/resources/local-local-absolute-2/package.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/resources/local-local-relative/other.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/resources/local-local-relative/package.dhall",
    "content": "let x = ./other.dhall in x"
  },
  {
    "path": "modules/imports/src/test/resources/local-remote/package.dhall",
    "content": "let any = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/List/any in any"
  },
  {
    "path": "modules/imports/src/test/resources/multiple-imports/other.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/resources/multiple-imports/other2.dhall",
    "content": "let x = 2 in x"
  },
  {
    "path": "modules/imports/src/test/resources/multiple-imports/package.dhall",
    "content": "let x = ./other.dhall\n\nlet y = ./other2.dhall\n\nin [x,y]"
  },
  {
    "path": "modules/imports/src/test/resources/text-import/package.dhall",
    "content": "let x = 1 in x"
  },
  {
    "path": "modules/imports/src/test/scala/org/dhallj/imports/CanonicalizationSuite.scala",
    "content": "package org.dhallj.imports\n\nimport java.net.URI\nimport java.nio.file.Paths\n\nimport cats.effect.IO\nimport cats.effect.unsafe.implicits.global\nimport munit.FunSuite\nimport org.dhallj.imports.Canonicalization.canonicalize\nimport org.dhallj.imports.ImportContext._\nimport org.dhallj.parser.DhallParser.parse\n\n/**\n * https://github.com/dhall-lang/dhall-lang/blob/master/standard/imports.md#canonicalization-of-directories\n */\nclass CanonicalizationSuite extends FunSuite {\n\n  val headers1 = parse(\"/headers1.dhall\")\n  val headers2 = parse(\"/headers2.dhall\")\n\n  test(\"Imports - Local, empty path\") {\n    assertEquals(canonicalize[IO](Local(Paths.get(\"/foo.dhall\"))).unsafeRunSync(), Local(Paths.get(\"/foo.dhall\")))\n  }\n\n  test(\"Imports - quoted\") {\n    assertEquals(canonicalize[IO](Local(Paths.get(\"/\\\"foo\\\"/\\\"bar.dhall\\\"\"))).unsafeRunSync(),\n                 Local(Paths.get(\"/foo/bar.dhall\"))\n    )\n  }\n\n  test(\"Paths - Trailing .\") {\n    assertEquals(canonicalize[IO](Local(Paths.get(\"/foo/./bar.dhall\"))).unsafeRunSync(),\n                 Local(Paths.get(\"/foo/bar.dhall\"))\n    )\n  }\n\n  test(\"Paths - Trailing ..\") {\n    assertEquals(canonicalize[IO](Local(Paths.get(\"/foo/bar/../baz.dhall\"))).unsafeRunSync(),\n                 Local(Paths.get(\"/foo/baz.dhall\"))\n    )\n  }\n\n  //TODO determine whether spec is correct on this\n  test(\"Paths - Root ..\") {\n    assertEquals(canonicalize[IO](Local(Paths.get(\"/..\"))).unsafeRunSync(), Local(Paths.get(\"/..\")))\n  }\n\n  test(\"Chaining - local / , local /\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"/foo/bar.dhall\")), Local(Paths.get(\"/bar/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"/bar/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local / , local ~\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"/foo/bar.dhall\")), Local(Paths.get(\"~/bar/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"~/bar/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local / , local .\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"/foo/bar.dhall\")), Local(Paths.get(\"./baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"/foo/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local / , local ..\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"./foo/x/bar.dhall\")), Local(Paths.get(\"../bar/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"./foo/bar/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local ~ , local /\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"~/foo/bar.dhall\")), Local(Paths.get(\"/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local ~ , local ~\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"~/foo/bar.dhall\")), Local(Paths.get(\"~/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"~/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local ~ , local .\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"~/foo/bar.dhall\")), Local(Paths.get(\"./baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"~/foo/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local ~ , local ..\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"~/foo/bar.dhall\")), Local(Paths.get(\"../baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"~/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local . , local /\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"./foo/bar.dhall\")), Local(Paths.get(\"/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local . , local ~\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"./foo/bar.dhall\")), Local(Paths.get(\"~/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"~/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local . , local .\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"./foo/bar.dhall\")), Local(Paths.get(\"./baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"./foo/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local . , local ..\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"./foo/bar.dhall\")), Local(Paths.get(\"../baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"./baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local .. , local /\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"../foo/bar.dhall\")), Local(Paths.get(\"/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local .. , local ~\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"../foo/bar.dhall\")), Local(Paths.get(\"~/baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"~/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local .. , local .\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"../foo/bar.dhall\")), Local(Paths.get(\"./baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"../foo/baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local .. , local ..\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"../foo/bar.dhall\")), Local(Paths.get(\"../baz.dhall\"))).unsafeRunSync(),\n      Local(Paths.get(\"../baz.dhall\"))\n    )\n  }\n\n  test(\"Chaining - local / remote\") {\n    assertEquals(\n      canonicalize[IO](Local(Paths.get(\"/foo/bar.dhall\")), Remote(new URI(\"http://foo.org/bar.dhall\"), headers1))\n        .unsafeRunSync(),\n      Remote(new URI(\"http://foo.org/bar.dhall\"), headers1)\n    )\n  }\n\n  test(\"Chaining - remote / remote absolute\") {\n    assertEquals(\n      canonicalize[IO](Remote(new URI(\"http://foo.org/bar.dhall\"), headers1),\n                       Remote(new URI(\"https://bar.com/bar/baz.dhall\"), headers2)\n      ).unsafeRunSync(),\n      Remote((new URI(\"https://bar.com/bar/baz.dhall\")), headers2)\n    )\n  }\n\n  test(\"Chaining - remote / local relative\") {\n    assertEquals(\n      canonicalize[IO](Remote(new URI(\"http://foo.org/bar.dhall\"), headers1), Local(Paths.get(\"./baz.dhall\")))\n        .unsafeRunSync(),\n      Remote(new URI(\"http://foo.org/baz.dhall\"), headers1)\n    )\n  }\n\n  //This is actually prohibited by the sanity check but we don't worry about it here\n  test(\"Chaining - remote / local absolute\") {\n    assertEquals(\n      canonicalize[IO](Remote(new URI(\"http://foo.org/bar.dhall\"), headers1), Local(Paths.get(\"/baz.dhall\")))\n        .unsafeRunSync(),\n      Local(Paths.get(\"/baz.dhall\"))\n    )\n  }\n\n}\n"
  },
  {
    "path": "modules/imports/src/test/scala/org/dhallj/imports/CorsComplianceCheckSuite.scala",
    "content": "package org.dhallj.imports\n\nimport java.net.URI\nimport java.nio.file.Paths\n\nimport cats.effect.IO\nimport cats.effect.unsafe.implicits.global\nimport munit.FunSuite\nimport org.dhallj.imports.ImportContext._\nimport org.http4s.{Header, Headers}\nimport org.typelevel.ci._\n\nclass CorsComplianceCheckSuite extends FunSuite {\n\n  val fooOrigin = new URI(\"http://foo.org/foo.dhall\")\n  val fooOrigin8080 = new URI(\"http://foo.org:8080/foo.dhall\")\n  val fooOrigin2 = new URI(\"http://foo.org/baz.dhall\")\n  val barOrigin = new URI(\"http://bar.org/bar.dhall\")\n\n  val localPath = Paths.get(\"/foo/bar.dhall\")\n\n  test(\"Remote - same origin\") {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null), Remote(fooOrigin2, null), Headers.empty).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin, allow *\") {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null),\n                            Remote(barOrigin, null),\n                            Headers(Header.Raw(ci\"Access-Control-Allow-Origin\", \"*\"))\n    ).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin, allow parent authority\") {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null),\n                            Remote(barOrigin, null),\n                            Headers(Header.Raw(ci\"Access-Control-Allow-Origin\", \"http://foo.org\"))\n    ).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin\".fail) {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null), Remote(barOrigin, null), Headers.empty).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin, cors parent different authority\".fail) {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null),\n                            Remote(barOrigin, null),\n                            Headers(Header.Raw(ci\"Access-Control-Allow-Origin\", \"http://bar.org\"))\n    ).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin, cors parent different scheme\".fail) {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null),\n                            Remote(barOrigin, null),\n                            Headers(Header.Raw(ci\"Access-Control-Allow-Origin\", \"https://foo.org\"))\n    ).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin, cors parent different port\".fail) {\n    CorsComplianceCheck[IO](Remote(fooOrigin, null),\n                            Remote(barOrigin, null),\n                            Headers(Header.Raw(ci\"Access-Control-Allow-Origin\", \"http://foo.org:8080\"))\n    ).unsafeRunSync()\n  }\n\n  test(\"Remote - different origin, cors parent different port 2\".fail) {\n    CorsComplianceCheck[IO](Remote(fooOrigin8080, null),\n                            Remote(barOrigin, null),\n                            Headers(Header.Raw(ci\"Access-Control-Allow-Origin\", \"http://foo.org\"))\n    ).unsafeRunSync()\n  }\n\n  test(\"Local\") {\n    CorsComplianceCheck[IO](Local(localPath), Remote(fooOrigin2, null), Headers.empty).unsafeRunSync()\n  }\n\n  test(\"Env\") {\n    CorsComplianceCheck[IO](Env(\"foo\"), Remote(fooOrigin2, null), Headers.empty).unsafeRunSync()\n  }\n}\n"
  },
  {
    "path": "modules/imports/src/test/scala/org/dhallj/imports/ImportCacheSuite.scala",
    "content": "package org.dhallj.imports\n\nimport java.nio.file.{Files, Path}\n\nimport cats.effect.IO\nimport cats.effect.unsafe.implicits.global\nimport munit.FunSuite\n\nclass ImportCacheSuite extends FunSuite {\n\n  val rootDir = FunFixture[(ImportCache[IO], Path)](\n    setup = { test =>\n      val rootDir = Files.createTempDirectory(test.name).resolve(\"dhall\")\n      ImportCache[IO](rootDir).unsafeRunSync().get -> rootDir\n    },\n    teardown = { case (_, rootDir) => }\n  )\n\n  val key = \"0f86d\".getBytes\n\n  val bytes: Array[Byte] = \"test\".getBytes\n\n  rootDir.test(\"Get-if-absent\") { case (cache, _) =>\n    val prog = cache.get(key)\n\n    assertEquals(prog.unsafeRunSync(), None)\n  }\n\n  rootDir.test(\"Get-if-present\") { case (cache, _) =>\n    val prog = cache.put(key, bytes) >> cache.get(key)\n\n    assert(prog.unsafeRunSync().exists(_.sameElements(bytes)))\n  }\n\n}\n"
  },
  {
    "path": "modules/imports/src/test/scala/org/dhallj/imports/ImportResolutionSuite.scala",
    "content": "package org.dhallj.imports\n\nimport java.security.MessageDigest\n\nimport cats.effect.{IO, Ref, Resource}\nimport cats.effect.unsafe.implicits.global\nimport cats.implicits._\nimport munit.FunSuite\nimport org.dhallj.core.Expr\nimport org.dhallj.core.binary.Decode\nimport org.dhallj.imports.syntax._\nimport org.dhallj.parser.DhallParser.parse\nimport org.http4s.blaze.client._\nimport org.http4s.client._\n\nclass ImportResolutionSuite extends FunSuite {\n\n  implicit val client: Resource[IO, Client[IO]] =\n    BlazeClientBuilder[IO](scala.concurrent.ExecutionContext.global).resource\n\n  test(\"Classpath import\") {\n    val expr = parse(\"let x = classpath:/local/package.dhall in x\")\n    val expected = parse(\"let x = 1 in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Quoted import\") {\n    val expr = parse(\"let x = classpath:/\\\"local\\\"/\\\"package.dhall\\\" in x\")\n    val expected = parse(\"let x = 1 in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Classpath -> classpath relative import\") {\n    val expr = parse(\"let x = classpath:/local-local-relative/package.dhall in x\")\n    val expected = parse(\"let x = 1 in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Classpath -> classpath absolute import\") {\n    val expr = parse(\"let x = classpath:/local-local-absolute/package.dhall in x\")\n    val expected = parse(\"let x = 1 in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Classpath -> remote import\") {\n    val expr = parse(\"let any = classpath:/local-remote/package.dhall in any Natural Natural/even [2,3,5]\")\n    val expected = parse(\"True\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Remote import\") {\n    val expr = parse(\n      \"let any = https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/List/any in any Natural Natural/even [2,3,5]\"\n    )\n    val expected = parse(\"True\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  //TODO - dependent on https://github.com/travisbrown/dhallj/issues/34\n  test(\"Quoted remote import\".fail) {\n    val expr = parse(\n      \"let any = https://raw.githubusercontent.com/\\\"dhall-lang\\\"/\\\"dhall-lang\\\"/\\\"master\\\"/\\\"Prelude\\\"/\\\"List\\\"/\\\"any\\\" in any Natural Natural/even [2,3,5]\"\n    )\n    val expected = parse(\"True\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Multiple imports\") {\n    val expr = parse(\"let x = classpath:/multiple-imports/package.dhall in x\")\n    val expected = parse(\"let x = [1,2] in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Import as text\") {\n    val expr = parse(\"let x = classpath:/text-import/package.dhall as Text in x\")\n    val expected = parse(\"\\\"let x = 1 in x\\\"\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Import as local location\") {\n    val expr = parse(\"let x = /foo/bar.dhall as Location in x\")\n    val expected =\n      parse(\n        \"< Local : Text | Remote : Text | Environment : Text | Missing >.Local \\\"/foo/bar.dhall\\\"\"\n      ).normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Import as remote location\") {\n    val expr = parse(\"let x = http://example.com/foo.dhall as Location in x\")\n    val expected = parse(\n      \"< Local : Text | Remote : Text | Environment : Text | Missing >.Remote \\\"http://example.com/foo.dhall\\\"\"\n    ).normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Import as env location\") {\n    val expr = parse(\"let x = env:foo as Location in x\")\n    val expected =\n      parse(\"< Local : Text | Remote : Text | Environment : Text | Missing >.Environment \\\"foo\\\"\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Cyclic imports\".fail) {\n    val expr = parse(\"let x = classpath:/cyclic-relative-paths/package.dhall in x\")\n    val expected = parse(\"True\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Cyclic imports - all relative\".fail) {\n    val expr = parse(\"let x = classpath:/cyclic-relative-paths/package.dhall in x\")\n    val expected = parse(\"True\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Alternate imports - first succeeds\") {\n    val expr = parse(\"let x = classpath:/alternate/package.dhall ? classpath:/alternate/other.dhall in x\")\n    val expected = parse(\"let x = 1 in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Alternate imports - first fails\") {\n\n    val expr = parse(\"let x = classpath:/alternate/not_present.dhall ? classpath:/alternate/package.dhall in x\")\n    val expected = parse(\"let x = 1 in x\").normalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Valid hash\") {\n\n    val expr = parse(\n      \"classpath:/hashed/package.dhall sha256:d60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15\"\n    )\n    val expected = parse(\"let x = 1 in x\").normalize.alphaNormalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Invalid hash\".fail) {\n\n    val expr = parse(\n      \"let x = classpath:/hashed/package.dhall sha256:e60d8415e36e86dae7f42933d3b0c4fe3ca238f057fba206c7e9fbf5d784fe15 in x\"\n    )\n    val expected = parse(\"let x = 1 in x\").normalize.alphaNormalize\n\n    assert(resolve(expr) == expected)\n  }\n\n  test(\"Read from cache, cached value present\") {\n    val cache = InMemoryCache()\n\n    val expected = parse(\"let x = 2 in x\")\n    val encoded = expected.normalize.alphaNormalize.getEncodedBytes\n    val hash = MessageDigest.getInstance(\"SHA-256\").digest(encoded)\n\n    val expr =\n      parse(\n        \"let x = classpath:/does-not-exist sha256:4caf97e8c445d4d4b5c5b992973e098ed4ae88a355915f5a59db640a589bc9cb in x\"\n      )\n\n    assert((cache.put(hash, encoded) >> resolveWithCustomCache(cache, expr)).unsafeRunSync() == expected)\n  }\n\n  test(\"Read from cache, incorrect hash\".fail) {\n    val cache = InMemoryCache()\n\n    val cached = parse(\"let x = 1 in x\")\n    val expected = parse(\"let x = 2 in x\")\n    val encoded = cached.normalize.alphaNormalize.getEncodedBytes\n    val hash =\n      MessageDigest\n        .getInstance(\"SHA-256\")\n        .digest(expected.normalize.getEncodedBytes) //Hash doesn't match what is stored\n\n    val expr =\n      parse(\n        \"let x = classpath:/does-not-exist sha256:4caf97e8c445d4d4b5c5b992973e098ed4ae88a355915f5a59db640a589bc9cb in x\"\n      )\n\n    assert((cache.put(hash, encoded) >> resolveWithCustomCache(cache, expr)).unsafeRunSync() == expected)\n  }\n\n  test(\"Write to cache\") {\n    val cache = InMemoryCache()\n\n    val expected = parse(\"let x = 2 in x\")\n    val encoded = expected.normalize.alphaNormalize.getEncodedBytes\n    val hash = MessageDigest.getInstance(\"SHA-256\").digest(encoded)\n\n    val expr = parse(\n      \"let x = classpath:/cache-write/package.dhall sha256:4caf97e8c445d4d4b5c5b992973e098ed4ae88a355915f5a59db640a589bc9cb in x\"\n    )\n\n    val prog = resolveWithCustomCache(cache, expr) >> cache.get(hash)\n\n    assert(prog.unsafeRunSync() match {\n      case None     => false\n      case Some(bs) => Decode.decode(bs) == expected\n    })\n  }\n\n  private def resolve(e: Expr): Expr =\n    client\n      .use { c =>\n        implicit val http: Client[IO] = c\n\n        e.resolveImports[IO].map(_.normalize)\n      }\n      .unsafeRunSync()\n\n  private def resolveWithCustomCache(cache: ImportCache[IO], e: Expr): IO[Expr] =\n    client.use { c =>\n      implicit val http: Client[IO] = c\n\n      Resolver.resolve(cache)(e)\n    }\n\n  private case class InMemoryCache() extends ImportCache[IO] {\n\n    private val store: Ref[IO, Map[List[Byte], Array[Byte]]] = Ref.unsafe(Map.empty)\n\n    override def get(key: Array[Byte]): IO[Option[Array[Byte]]] = store.get.map(_.get(key.toList))\n\n    override def put(key: Array[Byte], value: Array[Byte]): IO[Unit] = store.update(_ + (key.toList -> value))\n  }\n\n}\n"
  },
  {
    "path": "modules/imports/src/test/scala/org/dhallj/imports/ReferentialSanityCheckSuite.scala",
    "content": "package org.dhallj.imports\n\nimport java.net.URI\nimport java.nio.file.Paths\n\nimport cats.effect.IO\nimport cats.effect.unsafe.implicits.global\nimport munit.FunSuite\nimport org.dhallj.imports.ImportContext._\n\nclass ReferentialSanityCheckSuite extends FunSuite {\n\n  private val someUri = new URI(\"http://example.com/foo.dhall\")\n  private val somePath = Paths.get(\"/foo.dhall\")\n\n  test(\"Remote imports local\".fail) {\n    ReferentialSanityCheck[IO](Remote(someUri, null), Local(somePath)).unsafeRunSync()\n  }\n\n  test(\"Remote imports env\".fail) {\n    ReferentialSanityCheck[IO](Remote(someUri, null), Env(\"foo\")).unsafeRunSync()\n  }\n\n  test(\"Remote imports remote\") {\n    ReferentialSanityCheck[IO](Remote(someUri, null), Remote(someUri, null)).unsafeRunSync()\n  }\n\n  test(\"Remote imports missing\") {\n    ReferentialSanityCheck[IO](Remote(someUri, null), Missing).unsafeRunSync()\n  }\n\n  test(\"Remote imports classpath\".fail) {\n    ReferentialSanityCheck[IO](Remote(someUri, null), Classpath(somePath)).unsafeRunSync()\n  }\n\n  test(\"Local imports local\") {\n    ReferentialSanityCheck[IO](Local(somePath), Local(somePath)).unsafeRunSync()\n  }\n\n  test(\"Local imports env\") {\n    ReferentialSanityCheck[IO](Local(somePath), Env(\"foo\")).unsafeRunSync()\n  }\n\n  test(\"Local imports remote\") {\n    ReferentialSanityCheck[IO](Local(somePath), Remote(someUri, null)).unsafeRunSync()\n  }\n\n  test(\"Local imports missing\") {\n    ReferentialSanityCheck[IO](Local(somePath), Missing).unsafeRunSync()\n  }\n\n  test(\"Env imports local\") {\n    ReferentialSanityCheck[IO](Env(\"foo\"), Local(somePath)).unsafeRunSync()\n  }\n\n  test(\"Env imports env\") {\n    ReferentialSanityCheck[IO](Env(\"foo\"), Env(\"foo\")).unsafeRunSync()\n  }\n\n  test(\"Env imports remote\") {\n    ReferentialSanityCheck[IO](Env(\"foo\"), Remote(someUri, null)).unsafeRunSync()\n  }\n\n  test(\"Env imports missing\") {\n    ReferentialSanityCheck[IO](Env(\"foo\"), Missing).unsafeRunSync()\n  }\n}\n"
  },
  {
    "path": "modules/imports/src/test/scala/org/dhallj/imports/ToHeadersSuite.scala",
    "content": "package org.dhallj.imports\n\nimport munit.FunSuite\nimport org.dhallj.core.Expr\nimport org.http4s.{Header, Headers}\nimport org.typelevel.ci._\n\nimport scala.collection.JavaConverters._\n\nclass ToHeadersSuite extends FunSuite {\n\n  test(\"Success case\") {\n    val expr = Expr.makeNonEmptyListLiteral(\n      Array(\n        Expr.makeRecordLiteral(\n          Map(\"header\" -> Expr.makeTextLiteral(\"foo\"), \"value\" -> Expr.makeTextLiteral(\"bar\")).asJava.entrySet()\n        ),\n        Expr.makeRecordLiteral(\n          Map(\"header\" -> Expr.makeTextLiteral(\"baz\"), \"value\" -> Expr.makeTextLiteral(\"x\")).asJava.entrySet()\n        )\n      )\n    )\n\n    val expected = Headers(\n      List(\n        Header.Raw(ci\"foo\", \"bar\"),\n        Header.Raw(ci\"baz\", \"x\")\n      )\n    )\n\n    assertEquals(ToHeaders(expr), Some(expected))\n  }\n\n  test(\"Success case 2\") {\n    val expr = Expr.makeNonEmptyListLiteral(\n      Array(\n        Expr.makeRecordLiteral(\n          Map(\"mapKey\" -> Expr.makeTextLiteral(\"foo\"), \"mapValue\" -> Expr.makeTextLiteral(\"bar\")).asJava.entrySet()\n        ),\n        Expr.makeRecordLiteral(\n          Map(\"mapKey\" -> Expr.makeTextLiteral(\"baz\"), \"mapValue\" -> Expr.makeTextLiteral(\"x\")).asJava.entrySet()\n        )\n      )\n    )\n\n    val expected = Headers(\n      List(\n        Header.Raw(ci\"foo\", \"bar\"),\n        Header.Raw(ci\"baz\", \"x\")\n      )\n    )\n\n    assertEquals(ToHeaders(expr), Some(expected))\n  }\n\n  test(\"Failure case 1\") {\n    val expr = Expr.makeNonEmptyListLiteral(\n      Array(\n        Expr.makeRecordLiteral(\n          Map(\"header\" -> Expr.makeTextLiteral(\"foo\"), \"mapValue\" -> Expr.makeTextLiteral(\"bar\")).asJava.entrySet()\n        ),\n        Expr.makeRecordLiteral(\n          Map(\"mapKey\" -> Expr.makeTextLiteral(\"baz\"), \"value\" -> Expr.makeTextLiteral(\"x\")).asJava.entrySet()\n        )\n      )\n    )\n\n    assertEquals(ToHeaders(expr), None)\n  }\n\n  test(\"Failure case 2\") {\n    val expr = Expr.makeTextLiteral(\"foo\")\n\n    assertEquals(ToHeaders(expr), None)\n  }\n\n}\n"
  },
  {
    "path": "modules/imports-mini/src/main/java/org/dhallj/imports/mini/ResolutionVisitor.java",
    "content": "package org.dhallj.imports.mini;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport org.dhallj.core.DhallException.ParsingFailure;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Visitor;\nimport org.dhallj.parser.DhallParser;\n\nabstract class ResolutionVisitor extends Visitor.Identity {\n  private final Path currentPath;\n  protected final boolean integrityChecks;\n\n  ResolutionVisitor(Path currentPath, boolean integrityChecks) {\n    this.currentPath = currentPath;\n    this.integrityChecks = integrityChecks;\n  }\n\n  protected abstract String readContents(Path path) throws IOException, URISyntaxException;\n\n  protected abstract ResolutionVisitor withCurrentPath(Path newCurrentPath);\n\n  public void bind(String name, Expr type) {}\n\n  @Override\n  public Expr onOperatorApplication(Operator operator, Expr lhs, Expr rhs) {\n    if (operator.equals(Operator.IMPORT_ALT)) {\n      return lhs;\n    } else {\n      return Expr.makeOperatorApplication(operator, lhs, rhs);\n    }\n  }\n\n  @Override\n  public Expr onMissingImport(Expr.ImportMode mode, byte[] hash) {\n    Expr result;\n\n    if (mode.equals(Expr.ImportMode.LOCATION)) {\n      result = Expr.makeFieldAccess(Expr.Constants.LOCATION_TYPE, \"Missing\");\n    } else {\n      throw new Missing();\n    }\n\n    return checkHash(result, hash);\n  }\n\n  @Override\n  public Expr onEnvImport(String name, Expr.ImportMode mode, byte[] hash) {\n    Expr result;\n\n    if (mode.equals(Expr.ImportMode.LOCATION)) {\n      result =\n          Expr.makeApplication(\n              Expr.makeFieldAccess(Expr.Constants.LOCATION_TYPE, \"Environment\"),\n              Expr.makeTextLiteral(name));\n    } else {\n      String value = System.getenv(name);\n\n      if (value != null) {\n        if (mode.equals(Expr.ImportMode.RAW_TEXT)) {\n          result = Expr.makeTextLiteral(value);\n        } else {\n          try {\n            result = DhallParser.parse(value).accept(this);\n          } catch (ParsingFailure underlying) {\n            throw new WrappedParsingFailure(name, underlying);\n          }\n        }\n      } else {\n        throw new MissingEnv(name);\n      }\n    }\n\n    return checkHash(result, hash);\n  }\n\n  @Override\n  public Expr onLocalImport(Path path, Expr.ImportMode mode, byte[] hash) {\n    Expr result;\n\n    if (mode.equals(Expr.ImportMode.LOCATION)) {\n      result =\n          Expr.makeApplication(\n              Expr.makeFieldAccess(Expr.Constants.LOCATION_TYPE, \"Local\"),\n              Expr.makeTextLiteral(path.toString()));\n    } else {\n      Path resolvedPath = (currentPath == null) ? path : currentPath.resolveSibling(path);\n      String contents;\n\n      try {\n        contents = this.readContents(resolvedPath);\n      } catch (IOException underlying) {\n        throw new WrappedIOException(resolvedPath, underlying);\n      } catch (URISyntaxException underlying) {\n        throw new WrappedIOException(resolvedPath, underlying);\n      }\n\n      if (mode.equals(Expr.ImportMode.RAW_TEXT)) {\n        result = Expr.makeTextLiteral(contents);\n      } else {\n        try {\n          result = DhallParser.parse(contents).accept(this.withCurrentPath(resolvedPath));\n        } catch (ParsingFailure underlying) {\n          throw new WrappedParsingFailure(path.toString(), underlying);\n        }\n      }\n    }\n\n    return checkHash(result, hash);\n  }\n\n  @Override\n  public Expr onRemoteImport(URI url, Expr using, Expr.ImportMode mode, byte[] hash) {\n    Expr result;\n\n    if (mode.equals(Expr.ImportMode.LOCATION)) {\n      result =\n          Expr.makeApplication(\n              Expr.makeFieldAccess(Expr.Constants.LOCATION_TYPE, \"Remote\"),\n              Expr.makeTextLiteral(url.toString()));\n    } else {\n      throw new UnsupportedOperationException(\"Remote import resolution not currently supported\");\n    }\n\n    return checkHash(result, hash);\n  }\n\n  private final Expr checkHash(Expr result, byte[] expected) {\n    if (expected != null && this.integrityChecks) {\n      byte[] received = result.normalize().alphaNormalize().getHashBytes();\n      if (!Arrays.equals(received, expected)) {\n        throw new IntegrityCheckException(expected, received);\n      }\n    }\n    return result;\n  }\n\n  static final class Filesystem extends ResolutionVisitor {\n    Filesystem(Path currentPath, boolean integrityChecks) {\n      super(currentPath, integrityChecks);\n    }\n\n    protected ResolutionVisitor withCurrentPath(Path newCurrentPath) {\n      return new Filesystem(newCurrentPath, this.integrityChecks);\n    }\n\n    protected String readContents(Path path) throws IOException, URISyntaxException {\n      return new String(Files.readAllBytes(path));\n    }\n  }\n\n  static final class Resources extends ResolutionVisitor {\n    private final ClassLoader classLoader;\n\n    Resources(Path currentPath, boolean integrityChecks, ClassLoader classLoader) {\n      super(currentPath, integrityChecks);\n      this.classLoader = classLoader;\n    }\n\n    protected ResolutionVisitor withCurrentPath(Path newCurrentPath) {\n      return new Resources(newCurrentPath, this.integrityChecks, this.classLoader);\n    }\n\n    protected String readContents(Path path) throws IOException, URISyntaxException {\n      return new String(\n          Files.readAllBytes(Paths.get(this.classLoader.getResource(path.toString()).toURI())));\n    }\n  }\n\n  static final class WrappedParsingFailure extends RuntimeException {\n    String location;\n    ParsingFailure underlying;\n\n    WrappedParsingFailure(String location, ParsingFailure underlying) {\n      super(String.format(\"Can't parse import: %s\", location), underlying);\n      this.location = location;\n      this.underlying = underlying;\n    }\n  }\n\n  static final class WrappedIOException extends RuntimeException {\n    Path path;\n    Exception underlying;\n\n    WrappedIOException(Path path, Exception underlying) {\n      super(String.format(\"Missing file %s\", path), underlying);\n      this.path = path;\n      this.underlying = underlying;\n    }\n  }\n\n  static final class Missing extends RuntimeException {\n    Missing() {\n      super(\"No valid imports\");\n    }\n  }\n\n  static final class MissingEnv extends RuntimeException {\n    String name;\n\n    MissingEnv(String name) {\n      super(String.format(\"Missing environment variable %s\", name));\n      this.name = name;\n    }\n  }\n\n  static final class IntegrityCheckException extends RuntimeException {\n    final byte[] expected;\n    final byte[] received;\n\n    IntegrityCheckException(byte[] expected, byte[] received) {\n      super(\n          String.format(\n              \"Import integrity check failed (received: %s)\", Expr.Util.encodeHashBytes(received)));\n      this.expected = expected;\n      this.received = received;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/imports-mini/src/main/java/org/dhallj/imports/mini/Resolver.java",
    "content": "package org.dhallj.imports.mini;\n\nimport org.dhallj.core.DhallException.ResolutionFailure;\nimport org.dhallj.core.Expr;\nimport java.nio.file.Path;\n\npublic final class Resolver {\n  public static final Expr resolve(Expr expr, boolean integrityChecks, Path currentPath)\n      throws ResolutionFailure {\n    return resolveWithVisitor(expr, new ResolutionVisitor.Filesystem(currentPath, integrityChecks));\n  }\n\n  public static final Expr resolve(Expr expr, boolean integrityChecks) throws ResolutionFailure {\n    return resolve(expr, integrityChecks, null);\n  }\n\n  public static final Expr resolve(Expr expr) throws ResolutionFailure {\n    return resolve(expr, true);\n  }\n\n  public static final Expr resolveFromResources(\n      Expr expr, boolean integrityChecks, Path currentPath, ClassLoader classLoader)\n      throws ResolutionFailure {\n    return resolveWithVisitor(\n        expr, new ResolutionVisitor.Resources(currentPath, integrityChecks, classLoader));\n  }\n\n  public static final Expr resolveFromResources(\n      Expr expr, boolean integrityChecks, Path currentPath) throws ResolutionFailure {\n    return resolveFromResources(\n        expr, integrityChecks, currentPath, Resolver.class.getClassLoader());\n  }\n\n  public static final Expr resolveFromResources(Expr expr, boolean integrityChecks)\n      throws ResolutionFailure {\n    return resolveFromResources(expr, integrityChecks, null);\n  }\n\n  public static final Expr resolveFromResources(Expr expr) throws ResolutionFailure {\n    return resolveFromResources(expr, true);\n  }\n\n  private static final Expr resolveWithVisitor(Expr expr, ResolutionVisitor visitor)\n      throws ResolutionFailure {\n    Expr result;\n    try {\n      result = expr.accept(visitor);\n    } catch (ResolutionVisitor.WrappedParsingFailure e) {\n      throw new ResolutionFailure(e.getMessage(), e.underlying);\n    } catch (ResolutionVisitor.WrappedIOException e) {\n      throw new ResolutionFailure(e.getMessage(), e.underlying);\n    } catch (ResolutionVisitor.Missing e) {\n      throw new ResolutionFailure(e.getMessage());\n    } catch (ResolutionVisitor.MissingEnv e) {\n      throw new ResolutionFailure(e.getMessage());\n    } catch (ResolutionVisitor.IntegrityCheckException e) {\n      throw new ResolutionFailure(e.getMessage());\n    } catch (UnsupportedOperationException e) {\n      throw new ResolutionFailure(e.getMessage());\n    }\n    return result;\n  }\n}\n"
  },
  {
    "path": "modules/javagen/src/main/java/org/dhallj/javagen/Code.scala",
    "content": "package org.dhallj.javagen\n\ncase class Code(content: String, defs: Vector[Code] = Vector.empty) {\n  final private def replace(in: String, target: Int, newName: String): String = {\n    var last = 0\n    var next = in.indexOf(Code.marker, last)\n    val builder = new StringBuilder()\n\n    while (next >= 0) {\n      builder.append(in.substring(last, next))\n      val index = in.substring(next + Code.marker.length, next + Code.marker.length + Code.indexLength).toInt\n      if (index == target) {\n        builder.append(newName)\n      } else {\n        builder.append(in.substring(next, next + Code.marker.length + Code.indexLength))\n      }\n\n      last = next + Code.marker.length + Code.indexLength\n      next = in.indexOf(Code.marker, last)\n    }\n\n    builder.append(in.substring(last))\n    return builder.toString()\n  }\n\n  def mapContent(f: String => String): Code = Code(f(Code.makeIdentifier(0)), Vector(this))\n\n  def merge(other: Code)(f: (String, String) => String): Code =\n    Option(other) match {\n      case Some(otherValue) => Code(f(Code.makeIdentifier(0), Code.makeIdentifier(1)), Vector(this, other))\n      case None             => this.copy(content = f(content, \"null\"))\n    }\n\n  def merge(other0: Code, other1: Code)(f: (String, String, String) => String): Code =\n    Option(other1) match {\n      case Some(otherValue) =>\n        Code(f(Code.makeIdentifier(0), Code.makeIdentifier(1), Code.makeIdentifier(2)), Vector(this, other0, other1))\n      case None => Code(f(Code.makeIdentifier(0), Code.makeIdentifier(1), \"null\"), Vector(this, other0))\n    }\n\n  protected def toFields(known: Map[Code, (String, String)]): (String, Map[Code, (String, String)]) =\n    known.get(this) match {\n      case Some((name, impl)) => (name, known)\n      case None =>\n        val (newContent, newKnown) = this.defs.zipWithIndex.foldLeft((this.content, known)) {\n          case ((accContent, accKnown), (code, i)) =>\n            val (childName, newKnown) = code.toFields(accKnown)\n\n            (this.replace(accContent, i, childName), newKnown)\n        }\n\n        val nextName = Code.makeFieldName(newKnown.size)\n        (nextName, newKnown.updated(this, (nextName, newContent)))\n    }\n\n  def toClassDef(packageName: String, className: String): String = {\n    val (topLevelFieldName, fields) = toFields(Map.empty)\n\n    val fieldDefs = fields.values.toList\n      .sortBy(_._1)\n      .map { case (name, impl) =>\n        s\"  private static final Expr $name = $impl;\"\n      }\n      .mkString(\"\\n\")\n\n    s\"\"\"package $packageName;\n       |\n       |import java.math.BigInteger;\n       |import java.util.AbstractMap.SimpleImmutableEntry;\n       |import java.util.ArrayList;\n       |import java.util.List;\n       |import java.util.Map.Entry;\n       |import org.dhallj.core.Expr;\n       |import org.dhallj.core.Operator;\n       |\n       |public final class $className {\n       |$fieldDefs\n       |\n       |public static final Expr instance = $topLevelFieldName;\n       |}\n       |\"\"\".stripMargin\n  }\n}\n\nobject Code {\n  private[javagen] val marker: String = \"__\"\n  private[javagen] val indexLength: Int = 4\n  private[javagen] def makeIdentifier(n: Int): String =\n    String.format(s\"%s%0${indexLength}d\", marker, Int.box(n))\n  private[javagen] def makeFieldName(n: Int): String = f\"f$n%06d\"\n\n  def mergeAll(other: Vector[Code])(f: Vector[String] => String): Code =\n    Code(f(0.until(other.size).map(makeIdentifier).toVector), other)\n\n  def mergeAll[A](other: Vector[A])(extract: A => Option[Code])(f: Vector[(A, String)] => String): Code = {\n    var i = -1\n    val values = other.map { value =>\n      if (extract(value).isDefined) {\n        i += 1\n        (value, makeIdentifier(i))\n      } else {\n        (value, \"null\")\n      }\n    }\n\n    Code(f(values), other.flatMap(extract(_)))\n  }\n}\n"
  },
  {
    "path": "modules/javagen/src/main/java/org/dhallj/javagen/ToCodeVisitor.scala",
    "content": "package org.dhallj.javagen\n\nimport java.math.BigDecimal\nimport java.math.BigInteger\nimport java.net.URI\nimport java.nio.file.Path\nimport java.util.{List => JList}\nimport java.util.Map.Entry\nimport org.dhallj.core.Expr\nimport org.dhallj.core.Operator\nimport org.dhallj.core.Source\nimport org.dhallj.core.Visitor\nimport scala.collection.JavaConverters._\n\nobject ToCodeVisitor {\n  val instance: Visitor[Code] = new ToCodeVisitor\n}\n\nfinal class ToCodeVisitor extends Visitor.NoPrepareEvents[Code] {\n  private val constants = Set(\"Natural\", \"Integer\", \"Double\", \"True\", \"False\", \"Type\", \"List\", \"Text\")\n\n  private def unsupported: Nothing =\n    throw new RuntimeException(\"Java generation only supported for fully-interpreted expressions\")\n\n  def onNote(base: Code, source: Source): Code = base\n\n  def onNatural(self: Expr, value: BigInteger): Code = Code(s\"\"\"Expr.makeNaturalLiteral(new BigInteger(\"$value\"))\"\"\")\n  def onInteger(self: Expr, value: BigInteger): Code = Code(s\"\"\"Expr.makeIntegerLiteral(new BigInteger(\"$value\"))\"\"\")\n  def onDouble(self: Expr, value: Double): Code = Code(s\"\"\"Expr.makeDoubleLiteral($value)\"\"\")\n\n  def onDate(self: Expr, year: Int, month: Int, day: Int): Code = Code(s\"Expr.makeDateLiteral($year, $month, $day)\")\n  def onTime(self: Expr, hour: Int, minute: Int, second: Int, fractional: BigDecimal): Code = {\n    if (fractional.equals(BigDecimal.ZERO)) {\n      Code(s\"Expr.makeTimeLiteral($hour, $minute, $second, BigDecimal.ZERO)\")\n    } else {\n      Code(s\"Expr.makeTimeLiteral($hour, $minute, $second, new BigDecimal($fractional))\")\n    }\n  }\n  def onTimeZone(self: Expr, seconds: Int): Code = Code(s\"Expr.makeTimeZoneLiteral($seconds)\")\n\n  def onBuiltIn(self: Expr, name: String): Code = Code(\n    if (constants(name)) {\n      s\"\"\"Expr.Constants.${name.toUpperCase}\"\"\"\n    } else {\n      s\"\"\"Expr.makeBuiltIn(\"$name\")\"\"\"\n    }\n  )\n\n  def onIdentifier(self: Expr, name: String, index: Long): Code = Code(s\"\"\"Expr.makeIdentifier(\"$name\", $index)\"\"\")\n\n  def onLambda(name: String, tpe: Code, result: Code): Code =\n    result.merge(tpe) { case (resultContent, tpeContent) =>\n      s\"\"\"Expr.makeLambda(\"$name\", $tpeContent, $resultContent)\"\"\"\n    }\n\n  def onPi(name: String, tpe: Code, result: Code): Code =\n    result.merge(tpe) { case (resultContent, tpeContent) =>\n      s\"\"\"Expr.makePi(\"$name\", $tpeContent, $resultContent)\"\"\"\n    }\n\n  def onLet(bindings: JList[Expr.LetBinding[Code]], body: Code): Code = unsupported\n\n  private def escape(input: String): String = input.replace(\"\\\"\", \"\\\\\\\"\").replace(\"\\\\\\\\\", \"\\\\\\\\\\\\\\\\\")\n\n  def onText(parts: Array[String], interpolated: JList[Code]): Code =\n    if (parts.length == 1) {\n      Code(s\"\"\"Expr.makeTextLiteral(\"${escape(parts(0))}\")\"\"\")\n    } else {\n      Code.mergeAll(interpolated.asScala.toVector) { ids =>\n        val partArray = parts.map(part => \"\\\"\" + escape(part) + \"\\\"\").mkString(\", \")\n\n        s\"Expr.makeTextLiteral(new String[] {$partArray}, new Expr[] {${ids.mkString(\", \")}})\"\n      }\n    }\n\n  def onNonEmptyList(values: JList[Code]): Code = Code.mergeAll(values.asScala.toVector) { ids =>\n    s\"Expr.makeNonEmptyListLiteral(new Expr[] {${ids.mkString(\", \")}})\"\n  }\n\n  def onEmptyList(tpe: Code): Code =\n    tpe.mapContent(tpeContent => s\"Expr.makeEmptyListLiteral($tpeContent)\")\n\n  private def forFields(constructor: String, fields: JList[Entry[String, Code]]): Code =\n    if (fields.isEmpty) {\n      constructor match {\n        case \"makeRecordLiteral\" => Code(\"Expr.Constants.EMPTY_RECORD_LITERAL\")\n        case \"makeRecordType\"    => Code(\"Expr.Constants.EMPTY_RECORD_TYPE\")\n        case \"makeUnionType\"     => Code(\"Expr.Constants.EMPTY_UNION_TYPE\")\n      }\n    } else {\n      Code.mergeAll(fields.asScala.toVector)(entry => Option(entry.getValue)) { pairs =>\n        val entries = pairs\n          .map { case (entry, id) =>\n            s\"\"\"new SimpleImmutableEntry<String, Expr>(\"${entry.getKey}\", $id)\"\"\"\n          }\n          .mkString(\", \")\n\n        s\"Expr.$constructor(new Entry[] {$entries})\"\n      }\n    }\n\n  def onRecord(fields: JList[Entry[String, Code]]): Code = forFields(\"makeRecordLiteral\", fields)\n  def onRecordType(fields: JList[Entry[String, Code]]): Code = forFields(\"makeRecordType\", fields)\n  def onUnionType(fields: JList[Entry[String, Code]]): Code = forFields(\"makeUnionType\", fields)\n\n  def onFieldAccess(base: Code, fieldName: String): Code =\n    base.mapContent(baseContent => s\"\"\"Expr.makeFieldAccess($baseContent, \"$fieldName\")\"\"\")\n\n  def onProjection(base: Code, fieldNames: Array[String]): Code = {\n    val fieldNameArray = fieldNames.map(fieldName => \"\\\"\" + fieldName + \"\\\"\").mkString(\", \")\n\n    base.mapContent(baseContent => s\"\"\"Expr.makeProjection($baseContent, new String[] {${fieldNameArray}})\"\"\")\n  }\n\n  def onProjectionByType(base: Code, tpe: Code): Code =\n    base.merge(tpe) { case (baseContent, tpeContent) =>\n      s\"\"\"Expr.makeProjectionByType($baseContent, $tpeContent)\"\"\"\n    }\n\n  def onApplication(base: Code, args: JList[Code]): Code =\n    Code.mergeAll(base +: args.asScala.toVector) { case head +: tail =>\n      s\"Expr.makeApplication($head, new Expr[] {${tail.mkString(\", \")}})\"\n    }\n\n  def onOperatorApplication(operator: Operator, lhs: Code, rhs: Code): Code = {\n    val operatorCode = operator match {\n      case Operator.OR            => \"Operator.OR\"\n      case Operator.AND           => \"Operator.AND\"\n      case Operator.EQUALS        => \"Operator.EQUALS\"\n      case Operator.NOT_EQUALS    => \"Operator.NOT_EQUALS\"\n      case Operator.PLUS          => \"Operator.PLUS\"\n      case Operator.TIMES         => \"Operator.TIMES\"\n      case Operator.TEXT_APPEND   => \"Operator.TEXT_APPEND\"\n      case Operator.LIST_APPEND   => \"Operator.LIST_APPEND\"\n      case Operator.COMBINE       => \"Operator.COMBINE\"\n      case Operator.PREFER        => \"Operator.PREFER\"\n      case Operator.COMBINE_TYPES => \"Operator.COMBINE_TYPES\"\n      case Operator.IMPORT_ALT    => \"Operator.IMPORT_ALT\"\n      case Operator.EQUIVALENT    => \"Operator.EQUIVALENT\"\n      case Operator.COMPLETE      => \"Operator.COMPLETE\"\n    }\n\n    lhs.merge(rhs) { case (lhsContent, rhsContent) =>\n      s\"Expr.makeOperatorApplication($operatorCode, $lhsContent, $rhsContent)\"\n    }\n  }\n\n  def onIf(predicate: Code, thenValue: Code, elseValue: Code): Code = {\n    if (elseValue == null) throw new RuntimeException(predicate.toString());\n    predicate.merge(thenValue, elseValue) { case (predicateContent, thenValueContent, elseValueContent) =>\n      s\"\"\"Expr.makeIf($predicateContent, $thenValueContent, $elseValueContent)\"\"\"\n    }\n  }\n\n  def onAnnotated(base: Code, tpe: Code): Code = unsupported\n  def onAssert(base: Code): Code = unsupported\n  def onMerge(handlers: Code, union: Code, tpe: Code): Code =\n    handlers.merge(union, tpe) { case (handlersContent, unionContent, tpeContent) =>\n      s\"\"\"Expr.makeMerge($handlersContent, $unionContent, $tpeContent)\"\"\"\n\n    }\n\n  def onToMap(base: Code, tpe: Code): Code = unsupported\n  def onWith(base: Code, path: Array[String], value: Code): Code = unsupported\n  def onMissingImport(mode: Expr.ImportMode, hash: Array[Byte]): Code = unsupported\n  def onEnvImport(value: String, mode: Expr.ImportMode, hash: Array[Byte]): Code = unsupported\n  def onLocalImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): Code = unsupported\n  def onClasspathImport(path: Path, mode: Expr.ImportMode, hash: Array[Byte]): Code = unsupported\n  def onRemoteImport(url: URI, `using`: Code, mode: Expr.ImportMode, hash: Array[Byte]): Code = unsupported\n}\n"
  },
  {
    "path": "modules/javagen/src/main/java/org/dhallj/javagen/package.scala",
    "content": "package org.dhallj\n\nimport org.dhallj.core.Expr\n\npackage object javagen {\n  def toJavaCode(expr: Expr, packageName: String, className: String): String =\n    expr.accept(ToCodeVisitor.instance).toClassDef(packageName, className)\n}\n"
  },
  {
    "path": "modules/jawn/src/main/scala/org/dhallj/jawn/FacadeHandler.scala",
    "content": "package org.dhallj.jawn\n\nimport java.math.BigInteger\nimport java.util.{ArrayDeque, Deque}\nimport org.dhallj.core.converters.JsonHandler\nimport org.typelevel.jawn.{FContext, Facade}\n\nclass FacadeHandler[J](facade: Facade[J]) extends JsonHandler {\n  final protected[this] val stack: Deque[FContext[J]] = new ArrayDeque()\n  final protected[this] val position: Int = 0\n\n  protected[this] def addValue(value: J): Unit = {\n    if (stack.isEmpty) {\n      stack.push(facade.singleContext(position))\n    }\n    stack.peek.add(value, position)\n  }\n\n  final def result: J = stack.pop().finish(position)\n\n  final def onNull(): Unit = addValue(facade.jnull(position))\n  final def onBoolean(value: Boolean): Unit = addValue(if (value) facade.jtrue(position) else facade.jfalse(position))\n  def onNumber(value: BigInteger): Unit = addValue(facade.jnum(value.toString(), -1, -1, position))\n  def onDouble(value: Double): Unit =\n    if (java.lang.Double.isFinite(value)) {\n      val asString = java.lang.Double.toString(value)\n\n      addValue(facade.jnum(asString, asString.indexOf('.'), asString.indexOf('E'), position))\n    } else {\n      addValue(facade.jnull(position))\n    }\n\n  def onString(value: String): Unit = addValue(facade.jstring(value, position))\n\n  final def onArrayStart(): Unit = stack.push(facade.arrayContext(position))\n\n  final def onArrayEnd(): Unit = {\n    val current = stack.pop()\n\n    if (stack.isEmpty) {\n      stack.push(current)\n    } else {\n      stack.peek.add(current.finish(position), position)\n    }\n  }\n\n  final def onArrayElementGap(): Unit = ()\n\n  final def onObjectStart(): Unit = stack.push(facade.objectContext(position))\n\n  final def onObjectEnd(): Unit = {\n    val current = stack.pop()\n\n    if (stack.isEmpty) {\n      stack.push(current)\n    } else {\n      stack.peek.add(current.finish(position), position)\n    }\n  }\n\n  final def onObjectField(name: String): Unit = stack.peek.add(name, position)\n\n  final def onObjectFieldGap(): Unit = ()\n}\n"
  },
  {
    "path": "modules/jawn/src/main/scala/org/dhallj/jawn/JawnConverter.scala",
    "content": "package org.dhallj.jawn\n\nimport org.dhallj.core.Expr\nimport org.dhallj.core.converters.JsonConverter\nimport org.typelevel.jawn.Facade\n\nclass JawnConverter[J](facade: Facade[J]) {\n  def apply(expr: Expr): Option[J] = {\n    val handler = new FacadeHandler(facade)\n    val wasConverted = expr.accept(new JsonConverter(handler))\n\n    if (wasConverted) Some(handler.result) else None\n  }\n}\n"
  },
  {
    "path": "modules/jawn/src/test/scala/org/dhallj/jawn/JawnConverterSuite.scala",
    "content": "package org.dhallj.jawn\n\nimport io.circe.Json\nimport io.circe.jawn.CirceSupportParser\nimport io.circe.syntax._\nimport munit.ScalaCheckSuite\nimport org.dhallj.ast._\nimport org.dhallj.core.Expr\nimport org.dhallj.parser.DhallParser\nimport org.scalacheck.Prop\n\nclass JawnConverterSuite extends ScalaCheckSuite {\n  val converter = new JawnConverter(CirceSupportParser.facade)\n\n  property(\"convert integers\") {\n    Prop.forAll { (value: BigInt) =>\n      val asDhall = IntegerLiteral(value.underlying)\n      converter(asDhall) == Some(value.asJson)\n    }\n  }\n\n  property(\"convert lists of integers\") {\n    Prop.forAll { (values: Vector[BigInt]) =>\n      val asDhall = if (values.isEmpty) {\n        EmptyListLiteral(Expr.Constants.INTEGER)\n      } else {\n        val exprs = values.map(value => IntegerLiteral(value.underlying))\n        NonEmptyListLiteral(exprs.head, exprs.tail)\n      }\n      converter(asDhall) == Some(values.asJson)\n    }\n  }\n\n  property(\"convert lists of doubles\") {\n    Prop.forAll { (values: Vector[Double]) =>\n      val asDhall = if (values.isEmpty) {\n        EmptyListLiteral(Expr.Constants.DOUBLE)\n      } else {\n        val exprs = values.map(DoubleLiteral(_))\n        NonEmptyListLiteral(exprs.head, exprs.tail)\n      }\n      converter(asDhall) == Some(values.asJson)\n    }\n  }\n\n  property(\"convert lists of booleans\") {\n    Prop.forAll { (values: Vector[Boolean]) =>\n      val asDhall = if (values.isEmpty) {\n        EmptyListLiteral(Expr.Constants.BOOL)\n      } else {\n        val exprs = values.map(BoolLiteral(_))\n        NonEmptyListLiteral(exprs.head, exprs.tail)\n      }\n      converter(asDhall) == Some(values.asJson)\n    }\n  }\n\n  test(\"convert nested lists\") {\n    val expr = DhallParser.parse(\"[[]: List Bool]\")\n\n    assert(converter(expr) == Some(Json.arr(Json.arr())))\n  }\n\n  test(\"convert None\") {\n    val expr = DhallParser.parse(\"None Bool\")\n\n    assert(converter(expr) == Some(Json.Null))\n  }\n\n  test(\"convert Some\") {\n    val expr = DhallParser.parse(\"\"\"Some \"foo\"\"\"\")\n\n    assert(converter(expr) == Some(Json.fromString(\"foo\")))\n  }\n\n  test(\"convert records\") {\n    val expr1 = DhallParser.parse(\"{foo = [{bar = [1]}, {bar = [1, 2, 3]}]}\")\n    val Right(json1) = io.circe.jawn.parse(\"\"\"{\"foo\": [{\"bar\": [1]}, {\"bar\": [1, 2, 3]}]}\"\"\")\n\n    assert(converter(expr1) == Some(json1))\n  }\n\n  test(\"convert unions (nullary constructors)\") {\n    val expr1 = DhallParser.parse(\"[((\\\\(x: Natural) -> <foo: Bool|bar>) 1).bar]\").normalize()\n    val Right(json1) = io.circe.jawn.parse(\"\"\"[\"bar\"]\"\"\")\n\n    assert(converter(expr1) == Some(json1))\n  }\n\n  test(\"convert unions\") {\n    val expr1 = DhallParser.parse(\"[<foo: Bool|bar>.foo True]\").normalize()\n    val Right(json1) = io.circe.jawn.parse(\"\"\"[true]\"\"\")\n\n    assert(converter(expr1) == Some(json1))\n  }\n\n  test(\"fail safely on unconvertible expressions\") {\n    val expr1 = Lambda(\"x\", Expr.Constants.NATURAL, Identifier(\"x\"))\n\n    assert(converter(expr1) == None)\n  }\n}\n"
  },
  {
    "path": "modules/parser/BUILD",
    "content": "load(\"@com_google_j2cl//build_defs:rules.bzl\", \"j2cl_library\")\n\npackage(\n    default_visibility = [\"//visibility:public\"],\n)\n\nj2cl_library(\n    name = \"parser\",\n    srcs = glob([\n        \"src/main/java/org/dhallj/parser/*.java\",\n        \"src/main/java/org/dhallj/parser/support/*.java\",\n        \"target/javacc/*.java\",\n    ]),\n    deps = [\n        \"//javascript/jre:java_io\",\n        \"//javascript/jre:java_net\",\n        \"//javascript/jre:java_nio_file\",\n        \"//modules/core\",\n    ],\n)\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/DhallParser.java",
    "content": "package org.dhallj.parser;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport org.dhallj.core.Expr;\nimport org.dhallj.parser.support.Parser;\n\n/** Parses text input into Dhall expressions. */\npublic final class DhallParser {\n  private static final Charset UTF_8 = Charset.forName(\"UTF-8\");\n\n  public static Expr.Parsed parse(String input) {\n    return Parser.parse(input);\n  }\n\n  public static Expr.Parsed parse(InputStream input) throws IOException {\n    return parse(input, UTF_8);\n  }\n\n  public static Expr.Parsed parse(InputStream input, Charset charset) throws IOException {\n    return Parser.parse(input, charset);\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/Comment.java",
    "content": "package org.dhallj.parser.support;\n\nfinal class Comment {\n  private final String content;\n  private final int beginLine;\n  private final int beginColumn;\n  private final int endLine;\n  private final int endColumn;\n\n  Comment(String content, int beginLine, int beginColumn, int endLine, int endColumn) {\n    this.content = content;\n    this.beginLine = beginLine;\n    this.beginColumn = beginColumn;\n    this.endLine = endLine;\n    this.endColumn = endColumn;\n  }\n\n  public String getContent() {\n    return this.content;\n  }\n\n  public final int getBeginLine() {\n    return this.beginLine;\n  }\n\n  public final int getBeginColumn() {\n    return this.beginColumn;\n  }\n\n  public final int getEndLine() {\n    return this.endLine;\n  }\n\n  public final int getEndColumn() {\n    return this.endColumn;\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/LetBinding.java",
    "content": "package org.dhallj.parser.support;\n\nimport org.dhallj.core.Expr;\n\nfinal class LetBinding {\n  final String name;\n  final Expr.Parsed type;\n  final Expr.Parsed value;\n  final String text0;\n  final String text1;\n  final String text2;\n  final int beginLine;\n  final int beginColumn;\n\n  LetBinding(\n      String name,\n      Expr.Parsed type,\n      Expr.Parsed value,\n      String text0,\n      String text1,\n      String text2,\n      int beginLine,\n      int beginColumn) {\n    this.name = name;\n    this.type = type;\n    this.value = value;\n    this.text0 = text0;\n    this.text1 = text1;\n    this.text2 = text2;\n    this.beginLine = beginLine;\n    this.beginColumn = beginColumn;\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/OperatorPrecedenceTable.java",
    "content": "package org.dhallj.parser.support;\n\nimport org.dhallj.core.Operator;\n\nfinal class OperatorPrecedenceTable implements JavaCCParserConstants {\n  private static final int MAX_OPERATOR_TOKEN_KIND = 256;\n  private static final int[] table = new int[MAX_OPERATOR_TOKEN_KIND];\n\n  static {\n    for (int i = 0; i < MAX_OPERATOR_TOKEN_KIND; i++) {\n      table[i] = -1;\n    }\n\n    table[OR] = Operator.OR.getPrecedence();\n    table[AND] = Operator.AND.getPrecedence();\n    table[EQUALS] = Operator.EQUALS.getPrecedence();\n    table[NOT_EQUALS] = Operator.NOT_EQUALS.getPrecedence();\n    table[PLUS] = Operator.PLUS.getPrecedence();\n    table[TIMES] = Operator.TIMES.getPrecedence();\n    table[TEXT_APPEND] = Operator.TEXT_APPEND.getPrecedence();\n    table[LIST_APPEND] = Operator.LIST_APPEND.getPrecedence();\n    table[COMBINE] = Operator.COMBINE.getPrecedence();\n    table[PREFER] = Operator.PREFER.getPrecedence();\n    table[COMBINE_TYPES] = Operator.COMBINE_TYPES.getPrecedence();\n    table[IMPORT_ALT] = Operator.IMPORT_ALT.getPrecedence();\n    table[EQUIVALENT] = Operator.EQUIVALENT.getPrecedence();\n  }\n\n  static final int get(int tokenKind) {\n    if (tokenKind >= MAX_OPERATOR_TOKEN_KIND) {\n      return -1;\n    } else {\n      return table[tokenKind];\n    }\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/Parser.java",
    "content": "package org.dhallj.parser.support;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.Charset;\nimport org.dhallj.core.DhallException.ParsingFailure;\nimport org.dhallj.core.Expr;\n\n/** Wrapper for the JavaCC-generated parser. */\npublic final class Parser {\n  public static Expr.Parsed parse(String input) {\n    try {\n      return new JavaCCParser(new StringProvider(input)).TOP_LEVEL();\n    } catch (ParseException underlying) {\n      throw new ParsingFailure(underlying.getMessage(), underlying);\n    } catch (TokenMgrException underlying) {\n      throw new ParsingFailure(underlying.getMessage(), underlying);\n    }\n  }\n\n  public static Expr.Parsed parse(InputStream input, Charset charset) throws IOException {\n    try {\n      return new JavaCCParser(new StreamProvider(input, charset.name())).TOP_LEVEL();\n    } catch (ParseException underlying) {\n      throw new ParsingFailure(underlying.getMessage(), underlying);\n    } catch (TokenMgrException underlying) {\n      throw new ParsingFailure(underlying.getMessage(), underlying);\n    }\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/ParsingHelpers.java",
    "content": "package org.dhallj.parser.support;\n\nimport java.io.UnsupportedEncodingException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport org.dhallj.core.DhallException.ParsingFailure;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Source;\n\nfinal class ParsingHelpers {\n\n  private static Source sourceFromToken(Token token) {\n    return Source.fromString(\n        token.image, token.beginLine, token.beginColumn, token.endLine, token.endColumn);\n  }\n\n  private static Source sourceFromTokens(Token token1, Token token2) {\n    return Source.fromString(\n        token1.image + token2.image,\n        token1.beginLine,\n        token1.beginColumn,\n        token2.endLine,\n        token2.endColumn);\n  }\n\n  static final Expr.Parsed makeDoubleLiteral(Token token) {\n    double parsed = Double.parseDouble(token.image);\n\n    if (Double.isInfinite(parsed)\n        && !token.image.equals(\"Infinity\")\n        && !token.image.equals(\"-Infinity\")) {\n      throw new ParsingFailure(\"double out of bounds\");\n    }\n\n    return new Expr.Parsed(Expr.makeDoubleLiteral(parsed), sourceFromToken(token));\n  }\n\n  static final Expr.Parsed makeNaturalLiteral(Token token) {\n    BigInteger value =\n        token.image.startsWith(\"0x\")\n            ? new BigInteger(token.image.substring(2), 16)\n            : new BigInteger(token.image);\n\n    return new Expr.Parsed(Expr.makeNaturalLiteral(value), sourceFromToken(token));\n  }\n\n  static final Expr.Parsed makeIntegerLiteral(Token token) {\n    BigInteger value;\n\n    if (token.image.startsWith(\"0x\")) {\n      value = new BigInteger(token.image.substring(2), 16);\n    } else if (token.image.startsWith(\"-0x\")) {\n      value = new BigInteger(token.image.substring(3), 16).negate();\n    } else {\n      value = new BigInteger(token.image);\n    }\n\n    return new Expr.Parsed(Expr.makeIntegerLiteral(value), sourceFromToken(token));\n  }\n\n  static final boolean isValidDate(int year, int month, int day) {\n    if (month > 0 && month <= 12) {\n      if (day > 0 && day < 29) {\n        return true;\n      } else if (day == 29) {\n        // Deal with leap days.\n        if (month == 2) {\n          if (year % 4 != 0) {\n            return false;\n          } else if (year % 100 != 0) {\n            return true;\n          } else if (year % 400 != 0) {\n            return false;\n          } else {\n            return true;\n          }\n        } else {\n          return true;\n        }\n      } else if (day == 30) {\n        return month != 2;\n      } else if (day == 31) {\n        return month == 1\n            || month == 3\n            || month == 5\n            || month == 7\n            || month == 8\n            || month == 10\n            || month == 12;\n      } else {\n        return false;\n      }\n    } else {\n      return false;\n    }\n  }\n\n  static final Expr.Parsed makeDateLiteral(Token token) {\n    int year = Integer.parseInt(token.image.substring(0, 4));\n    int month = Integer.parseInt(token.image.substring(5, 7));\n    int day = Integer.parseInt(token.image.substring(8, 10));\n\n    if (!isValidDate(year, month, day)) {\n      throw new ParsingFailure(\"Invalid temporal literal\");\n    }\n\n    return new Expr.Parsed(Expr.makeDateLiteral(year, month, day), sourceFromToken(token));\n  }\n\n  static final Expr.Parsed makeTimeZoneLiteral(Token token) {\n    boolean positive = token.image.charAt(0) == '+';\n    int hour = Integer.parseInt(token.image.substring(1, 3));\n    int minute = Integer.parseInt(token.image.substring(4, 6));\n\n    if (hour > 23 || minute > 59) {\n      throw new ParsingFailure(\"Invalid temporal literal\");\n    }\n\n    int seconds = hour * 60 + minute;\n    int value = positive ? seconds : -seconds;\n\n    return new Expr.Parsed(Expr.makeTimeZoneLiteral(value), sourceFromToken(token));\n  }\n\n  static final Expr.Parsed makeTimeLiteral(Token token, Token timeZone) {\n    int hour = Integer.parseInt(token.image.substring(0, 2));\n    int minute = Integer.parseInt(token.image.substring(3, 5));\n    int second = Integer.parseInt(token.image.substring(6, 8));\n    BigDecimal fractional;\n\n    if (hour > 23 || minute > 59 || second > 59) {\n      throw new ParsingFailure(\"Invalid temporal literal\");\n    }\n\n    if (token.image.length() > 8) {\n      fractional = new BigDecimal(token.image.substring(8));\n    } else {\n      fractional = BigDecimal.ZERO;\n    }\n\n    Expr time = Expr.makeTimeLiteral(hour, minute, second, fractional);\n\n    if (timeZone != null) {\n      int value;\n\n      if (timeZone.image.equals(\"z\") || timeZone.image.equals(\"Z\")) {\n        value = 0;\n      } else if (timeZone.image.startsWith(\"+\") || timeZone.image.startsWith(\"-\")) {\n        boolean positive = timeZone.image.charAt(0) == '+';\n        int tzHour = Integer.parseInt(timeZone.image.substring(1, 3));\n        int tzMinute = Integer.parseInt(timeZone.image.substring(4, 6));\n\n        if (tzHour > 23 || tzMinute > 59) {\n          throw new ParsingFailure(\"Invalid temporal literal\");\n        }\n\n        int seconds = tzHour * 60 + tzMinute;\n        value = positive ? seconds : -seconds;\n      } else {\n        // Necessary to work around generated code size limits.\n        throw new ParsingFailure(\"Invalid temporal offset: \" + timeZone.image);\n      }\n\n      List<Entry<String, Expr>> fields = new ArrayList<Entry<String, Expr>>(2);\n      fields.add(new SimpleImmutableEntry<>(\"time\", time));\n      fields.add(new SimpleImmutableEntry<>(\"timeZone\", Expr.makeTimeZoneLiteral(value)));\n\n      return new Expr.Parsed(Expr.makeRecordLiteral(fields), sourceFromTokens(token, timeZone));\n    } else {\n      return new Expr.Parsed(time, sourceFromToken(token));\n    }\n  }\n\n  static final Expr.Parsed makeDateTimeLiteral(Token token, Token timeZone) {\n    int year = Integer.parseInt(token.image.substring(0, 4));\n    int month = Integer.parseInt(token.image.substring(5, 7));\n    int day = Integer.parseInt(token.image.substring(8, 10));\n\n    int hour = Integer.parseInt(token.image.substring(11, 13));\n    int minute = Integer.parseInt(token.image.substring(14, 16));\n    int second = Integer.parseInt(token.image.substring(17, 19));\n    BigDecimal fractional;\n\n    if (!isValidDate(year, month, day) || hour > 23 || minute > 59 || second > 59) {\n      throw new ParsingFailure(\"Invalid temporal literal\");\n    }\n\n    if (token.image.length() > 19) {\n      fractional = new BigDecimal(token.image.substring(19));\n    } else {\n      fractional = BigDecimal.ZERO;\n    }\n\n    List<Entry<String, Expr>> fields = new ArrayList<Entry<String, Expr>>(2);\n    fields.add(new SimpleImmutableEntry<>(\"date\", Expr.makeDateLiteral(year, month, day)));\n    fields.add(\n        new SimpleImmutableEntry<>(\"time\", Expr.makeTimeLiteral(hour, minute, second, fractional)));\n\n    if (timeZone != null) {\n      int value;\n\n      if (timeZone.image.equals(\"z\") || timeZone.image.equals(\"Z\")) {\n        value = 0;\n      } else if (timeZone.image.startsWith(\"+\") || timeZone.image.startsWith(\"-\")) {\n        boolean positive = timeZone.image.charAt(0) == '+';\n        int tzHour = Integer.parseInt(timeZone.image.substring(1, 3));\n        int tzMinute = Integer.parseInt(timeZone.image.substring(4, 6));\n\n        if (tzHour > 23 || tzMinute > 59) {\n          throw new ParsingFailure(\"Invalid temporal literal\");\n        }\n\n        int seconds = tzHour * 60 + tzMinute;\n        value = positive ? seconds : -seconds;\n      } else {\n        // Necessary to work around generated code size limits.\n        throw new ParsingFailure(\"Invalid temporal offset: \" + timeZone.image);\n      }\n\n      fields.add(new SimpleImmutableEntry<>(\"timeZone\", Expr.makeTimeZoneLiteral(value)));\n    }\n\n    Source source = timeZone == null ? sourceFromToken(token) : sourceFromTokens(token, timeZone);\n\n    return new Expr.Parsed(Expr.makeRecordLiteral(fields), source);\n  }\n\n  private static String unescapeText(String in) {\n    StringBuilder builder = new StringBuilder();\n    for (int i = 0; i < in.length(); i++) {\n      if (in.charAt(i) == '\\\\') {\n        i += 1;\n        char next = in.charAt(i);\n        if (next == '\"' || next == '$' || next == '/') {\n          builder.append(next);\n        } else if (next == 'u') {\n          char escapeFirst = in.charAt(i + 1);\n\n          if (escapeFirst == '{') {\n            int len = 0;\n            while (in.charAt(i + 2 + len) != '}') {\n              len += 1;\n            }\n\n            int code = Integer.parseInt(in.substring(i + 2, i + 2 + len), 16);\n            builder.appendCodePoint(code);\n            i += len + 2;\n          } else {\n            int code = Integer.parseInt(in.substring(i + 1, i + 5), 16);\n            builder.append((char) code);\n            i += 4;\n          }\n        } else {\n          builder.append('\\\\');\n          builder.append(next);\n        }\n      } else {\n        builder.append(in.charAt(i));\n      }\n    }\n    return builder.toString();\n  }\n\n  static final Expr.Parsed makeTextLiteral(\n      List<Entry<String, Expr.Parsed>> chunks, Token first, Token last) {\n    // TODO: fix source.\n    Source source =\n        Source.fromString(\"\", first.beginLine, first.beginColumn, last.endLine, last.endColumn);\n\n    List<String> parts = new ArrayList<>(1);\n    List<Expr> interpolated = new ArrayList<>();\n    boolean lastWasInterpolated = true;\n\n    for (Entry<String, Expr.Parsed> chunk : chunks) {\n      if (chunk.getKey() == null) {\n        if (lastWasInterpolated) {\n          parts.add(\"\");\n        }\n        interpolated.add(chunk.getValue());\n        lastWasInterpolated = true;\n      } else {\n        parts.add(unescapeText(chunk.getKey()));\n        lastWasInterpolated = false;\n      }\n    }\n\n    if (interpolated.size() == parts.size()) {\n      parts.add(\"\");\n    }\n\n    return new Expr.Parsed(\n        Expr.makeTextLiteral(parts.toArray(new String[parts.size()]), (List) interpolated), source);\n  }\n\n  static final void dedent(String[] input) {\n    List<Character> candidate = null;\n    String[][] partLines = new String[input.length][];\n\n    for (int i = 0; i < input.length; i += 1) {\n      String part = input[i].replace(\"\\r\\n\", \"\\n\");\n      String[] lines = part.split(\"\\n\", -1);\n      partLines[i] = lines;\n\n      for (int j = (i == 0) ? 0 : 1; j < lines.length; j += 1) {\n        String line = lines[j];\n\n        if (line.length() > 0 || j == lines.length - 1) {\n          if (candidate == null) {\n            candidate = new ArrayList<>();\n            for (int k = 0; k < line.length(); k += 1) {\n              char c = line.charAt(k);\n              if (c == ' ' || c == '\\t') {\n                candidate.add(c);\n              } else {\n                break;\n              }\n            }\n          } else {\n            for (int k = 0; k < candidate.size(); k += 1) {\n              if (k == line.length() || line.charAt(k) != candidate.get(k).charValue()) {\n                candidate = candidate.subList(0, k);\n                break;\n              }\n            }\n          }\n        }\n      }\n    }\n\n    int stripCount = candidate == null ? 0 : candidate.size();\n\n    if (stripCount == 0) {\n      for (int i = 0; i < input.length; i += 1) {\n        input[i] = reEscape(input[i]);\n      }\n    } else {\n      StringBuilder builder = new StringBuilder();\n\n      for (int i = 0; i < input.length; i += 1) {\n        builder.setLength(0);\n\n        String[] lines = partLines[i];\n\n        for (int j = 0; j < lines.length; j += 1) {\n          if (lines[j].length() != 0) {\n            if (i > 0 && j == 0) {\n              builder.append(lines[j]);\n            } else {\n              builder.append(lines[j].substring(stripCount));\n            }\n          }\n          if (j < lines.length - 1) {\n            builder.append(\"\\n\");\n          }\n        }\n\n        input[i] = reEscape(builder.toString());\n      }\n    }\n  }\n\n  static final String reEscape(String input) {\n    return input.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\n\", \"\\\\n\").replace(\"\\t\", \"\\\\t\");\n  }\n\n  static final Expr.Parsed makeSingleQuotedTextLiteral(\n      List<Entry<String, Expr.Parsed>> chunks, Token first) {\n    // TODO: fix source.\n    Source source = sourceFromToken(first);\n\n    Collections.reverse(chunks);\n\n    List<String> parts = new ArrayList<>(1);\n    List<Expr> interpolated = new ArrayList<>();\n\n    for (Entry<String, Expr.Parsed> chunk : chunks) {\n      if (chunk.getKey() == null) {\n        if (parts.isEmpty()) {\n          parts.add(\"\");\n        }\n        interpolated.add(chunk.getValue());\n      } else {\n        if (parts.size() > interpolated.size()) {\n          parts.set(parts.size() - 1, parts.get(parts.size() - 1) + chunk.getKey());\n        } else {\n          parts.add(chunk.getKey());\n        }\n      }\n    }\n\n    if (interpolated.size() == parts.size()) {\n      parts.add(\"\");\n    }\n\n    String[] partArray = parts.toArray(new String[parts.size()]);\n    dedent(partArray);\n\n    return new Expr.Parsed(Expr.makeTextLiteral(partArray, (List) interpolated), source);\n  }\n\n  static final Expr.Parsed makeApplication(Expr.Parsed base, Expr.Parsed arg, Token whsp) {\n    return new Expr.Parsed(Expr.makeApplication(base, arg), new ESESource(base, whsp.image, arg));\n  }\n\n  static final Expr.Parsed makeOperatorApplication(\n      Operator operator,\n      Expr.Parsed lhs,\n      Expr.Parsed rhs,\n      String operatorString,\n      Token whsp0,\n      Token whsp1) {\n    StringBuilder builder = new StringBuilder();\n    if (whsp0 != null) {\n      builder.append(whsp0.image);\n    }\n    builder.append(operatorString);\n    if (whsp1 != null) {\n      builder.append(whsp1.image);\n    }\n\n    Source source = new ESESource(lhs, builder.toString(), rhs);\n\n    return new Expr.Parsed(Expr.makeOperatorApplication(operator, lhs, rhs), source);\n  }\n\n  static final Expr.Parsed makeAnnotated(\n      Expr.Parsed base, Expr.Parsed tpe, Token whsp0, Token whsp1) {\n    StringBuilder builder = new StringBuilder();\n    if (whsp0 != null) {\n      builder.append(whsp0.image);\n    }\n    builder.append(':');\n    builder.append(whsp1.image);\n\n    Source source = new ESESource(base, builder.toString(), tpe);\n\n    return new Expr.Parsed(Expr.makeAnnotated(base, tpe), source);\n  }\n\n  static final Expr.Parsed makeToMap(\n      Expr.Parsed base, Expr.Parsed tpe, Token first, Token whsp0, Token whsp1, Token whsp2) {\n    StringBuilder builder = new StringBuilder();\n    if (whsp1 != null) {\n      builder.append(whsp1.image);\n    }\n    if (whsp2 != null) {\n      builder.append(\":\");\n      builder.append(whsp2.image);\n    }\n    Source source;\n\n    if (tpe != null) {\n      source =\n          new SESESource(\n              first.image + whsp0.image,\n              base,\n              builder.toString(),\n              tpe,\n              first.beginLine,\n              first.beginColumn);\n    } else {\n      source = new SESource(first.image + whsp0.image, base, first.beginLine, first.beginColumn);\n    }\n\n    return new Expr.Parsed(Expr.makeToMap(base, tpe), source);\n  }\n\n  static final Expr.Parsed makeToMap(Expr.Parsed base, Token first, Token whsp) {\n    Source source =\n        new SESource(first.image + whsp.image, base, first.beginLine, first.beginColumn);\n\n    return new Expr.Parsed(Expr.makeToMap(base), source);\n  }\n\n  static final Expr.Parsed makeMerge(\n      Expr.Parsed left,\n      Expr.Parsed right,\n      Expr.Parsed tpe,\n      Token first,\n      Token whsp0,\n      Token whsp1,\n      Token whsp2,\n      Token whsp3) {\n    Source source;\n\n    if (tpe != null) {\n      StringBuilder builder = new StringBuilder();\n      if (whsp2 != null) {\n        builder.append(whsp2.image);\n      }\n      builder.append(\":\");\n      builder.append(whsp3.image);\n      source =\n          new SESESESource(\n              first.image + whsp0.image,\n              left,\n              whsp1.image,\n              right,\n              builder.toString(),\n              tpe,\n              first.beginLine,\n              first.beginColumn);\n    } else {\n      source =\n          new SESESource(\n              first.image + whsp0.image,\n              left,\n              whsp1.image,\n              right,\n              first.beginLine,\n              first.beginColumn);\n    }\n\n    return new Expr.Parsed(Expr.makeMerge(left, right, tpe), source);\n  }\n\n  static final Expr.Parsed makeLambda(\n      String param, Expr.Parsed input, Expr.Parsed result, Token first) {\n    // TODO: text is empty.\n    Source source =\n        Source.fromString(\n            \"\",\n            first.beginLine,\n            first.beginColumn,\n            result.getSource().getEndLine(),\n            result.getSource().getEndColumn());\n\n    return new Expr.Parsed(Expr.makeLambda(param, input, result), source);\n  }\n\n  static final Expr.Parsed makePi(\n      String param, Expr.Parsed input, Expr.Parsed result, Token first) {\n    // TODO: text is empty.\n    Source source =\n        Source.fromString(\n            \"\",\n            first.beginLine,\n            first.beginColumn,\n            result.getSource().getEndLine(),\n            result.getSource().getEndColumn());\n\n    return new Expr.Parsed(Expr.makePi(param, input, result), source);\n  }\n\n  static final Expr.Parsed makePi(Expr.Parsed input, Expr.Parsed result) {\n    // TODO: text is empty.\n    Source source =\n        Source.fromString(\n            \"\",\n            input.getSource().getBeginLine(),\n            input.getSource().getBeginColumn(),\n            result.getSource().getEndLine(),\n            result.getSource().getEndColumn());\n\n    return new Expr.Parsed(Expr.makePi(input, result), source);\n  }\n\n  static final Expr.Parsed makeIf(\n      Expr.Parsed cond, Expr.Parsed thenValue, Expr.Parsed elseValue, Token first) {\n    // TODO: text is empty.\n    Source source =\n        Source.fromString(\n            \"\",\n            first.beginLine,\n            first.beginColumn,\n            elseValue.getSource().getEndLine(),\n            elseValue.getSource().getEndColumn());\n\n    return new Expr.Parsed(Expr.makeIf(cond, thenValue, elseValue), source);\n  }\n\n  static final Expr.Parsed makeLet(List<LetBinding> bindings, Expr.Parsed body, String whsp) {\n    Collections.reverse(bindings);\n    Expr.Parsed current = body;\n    String extraText2 = whsp;\n\n    for (LetBinding binding : bindings) {\n      Source source;\n      if (binding.type == null) {\n        source =\n            new SESESource(\n                binding.text1,\n                binding.value,\n                binding.text2 + extraText2,\n                current,\n                binding.beginLine,\n                binding.beginColumn);\n      } else {\n\n        source =\n            new SESESESource(\n                binding.text0,\n                binding.type,\n                binding.text1,\n                binding.value,\n                binding.text2 + extraText2,\n                current,\n                binding.beginLine,\n                binding.beginColumn);\n      }\n\n      current =\n          new Expr.Parsed(Expr.makeLet(binding.name, binding.type, binding.value, current), source);\n      extraText2 = \"\";\n    }\n\n    return current;\n  }\n\n  static Expr.Parsed makeAssert(Expr.Parsed base, Token first, Token whsp0, Token whsp1) {\n    StringBuilder builder = new StringBuilder(\"assert\");\n    if (whsp0 != null) {\n      builder.append(whsp0.image);\n    }\n    builder.append(':');\n    builder.append(whsp1.image);\n    Source source = new SESource(builder.toString(), base, first.beginLine, first.beginColumn);\n\n    return new Expr.Parsed(Expr.makeAssert(base), source);\n  }\n\n  static Expr.Parsed makeFieldAccess(\n      Expr.Parsed base, String fieldName, Token whsp0, Token whsp1, int endLine, int endColumn) {\n    StringBuilder builder = new StringBuilder();\n    if (whsp0 != null) {\n      builder.append(whsp0.image);\n    }\n    builder.append('.');\n    if (whsp1 != null) {\n      builder.append(whsp1.image);\n    }\n    builder.append(fieldName);\n    Source source = new ESSource(base, builder.toString(), endLine, endColumn);\n\n    return new Expr.Parsed(Expr.makeFieldAccess(base, fieldName), source);\n  }\n\n  static Expr.Parsed makeProjection(\n      Expr.Parsed base, List<String> fieldNames, int endLine, int endColumn) {\n    // TODO: text is empty.\n    Source source =\n        Source.fromString(\n            \"\",\n            base.getSource().getBeginLine(),\n            base.getSource().getBeginColumn(),\n            endLine,\n            endColumn);\n\n    return new Expr.Parsed(\n        Expr.makeProjection(base, fieldNames.toArray(new String[fieldNames.size()])), source);\n  }\n\n  static Expr.Parsed makeProjectionByType(\n      Expr.Parsed base, Expr.Parsed tpe, int endLine, int endColumn) {\n    // TODO: text is empty.\n    Source source =\n        Source.fromString(\n            \"\",\n            base.getSource().getBeginLine(),\n            base.getSource().getBeginColumn(),\n            endLine,\n            endColumn);\n\n    return new Expr.Parsed(Expr.makeProjectionByType(base, tpe), source);\n  }\n\n  private static final boolean isBuiltIn(String input) {\n    return input.charAt(0) != '`' && Expr.Constants.isBuiltIn(input);\n  }\n\n  private static final String unescapeLabel(String input) {\n    return (input.charAt(0) != '`') ? input : input.substring(1, input.length() - 1);\n  }\n\n  static final Expr.Parsed makeBuiltInOrIdentifier(Token value) {\n    if (isBuiltIn(value.image)) {\n      return new Expr.Parsed(Expr.makeBuiltIn(value.image), sourceFromToken(value));\n    } else {\n      return new Expr.Parsed(\n          Expr.makeIdentifier(unescapeLabel(value.image)), sourceFromToken(value));\n    }\n  }\n\n  static final Expr.Parsed makeIdentifier(Token value, Token whsp0, Token whsp1, Token index) {\n    StringBuilder builder = new StringBuilder();\n    builder.append(value.image);\n    if (whsp0 != null) {\n      builder.append(whsp0.image);\n    }\n    builder.append(\"@\");\n    if (whsp1 != null) {\n      builder.append(whsp1.image);\n    }\n    builder.append(index.image);\n    Source source =\n        Source.fromString(\n            builder.toString(), value.beginLine, value.beginColumn, index.endLine, index.endColumn);\n\n    long indexValue =\n        index.image.startsWith(\"0x\")\n            ? Long.parseLong(index.image.substring(2), 16)\n            : Long.parseLong(index.image);\n\n    return new Expr.Parsed(Expr.makeIdentifier(unescapeLabel(value.image), indexValue), source);\n  }\n\n  static final Expr.Parsed makeRecordLiteral(\n      List<Entry<List<String>, Expr.Parsed>> fields, Token first, Token last) {\n    // TODO: Get actual last token in all cases.\n    int endLine = (last == null) ? first.endLine : last.endLine;\n    int endColumn = (last == null) ? first.endColumn : last.endColumn;\n\n    // TODO: text is empty.\n    Source source = Source.fromString(\"\", first.beginLine, first.beginColumn, endLine, endColumn);\n\n    List<Entry<String, Expr>> dedotted = new ArrayList<>(fields.size());\n\n    for (Entry<List<String>, Expr.Parsed> entry : fields) {\n      List<String> parts = entry.getKey();\n      String firstPart = parts.remove(0);\n\n      Expr maybePunnedValue = entry.getValue();\n      Expr value;\n      if (maybePunnedValue == null) {\n        // Record puns can't be dotted.\n        value = Expr.makeIdentifier(firstPart);\n      } else {\n        value = maybePunnedValue;\n      }\n\n      if (parts.isEmpty()) {\n        dedotted.add(new SimpleImmutableEntry<>(firstPart, value));\n      } else {\n        Collections.reverse(parts);\n        Expr current = value;\n\n        for (String part : parts) {\n          current = Expr.makeRecordLiteral(part, current);\n        }\n        dedotted.add(new SimpleImmutableEntry<>(firstPart, current));\n      }\n    }\n\n    List<Entry<String, Expr>> desugared = new ArrayList<>(dedotted.size());\n    Set<String> seen = new HashSet();\n\n    for (int i = 0; i < dedotted.size(); i++) {\n      Entry<String, Expr> entry = dedotted.get(i);\n      String key = entry.getKey();\n\n      if (!seen.contains(key)) {\n        Expr current = entry.getValue();\n\n        for (int j = i + 1; j < dedotted.size(); j++) {\n          Entry<String, Expr> other = dedotted.get(j);\n\n          if (other.getKey().equals(entry.getKey())) {\n            current = Expr.makeOperatorApplication(Operator.COMBINE, current, other.getValue());\n          }\n        }\n\n        desugared.add(new SimpleImmutableEntry<>(key, current));\n\n        seen.add(key);\n      }\n    }\n\n    return new Expr.Parsed(Expr.makeRecordLiteral(desugared), source);\n  }\n\n  static final Expr.Parsed makeRecordType(\n      List<Entry<String, Expr.Parsed>> fields, Token first, Token last) {\n    // TODO: Get actual last token in all cases.\n    int endLine = (last == null) ? first.endLine : last.endLine;\n    int endColumn = (last == null) ? first.endColumn : last.endColumn;\n\n    // TODO: text is empty.\n    Source source = Source.fromString(\"\", first.beginLine, first.beginColumn, endLine, endColumn);\n\n    return new Expr.Parsed(Expr.makeRecordType((List) fields), source);\n  }\n\n  static final Expr.Parsed makeUnionType(\n      List<Entry<String, Expr.Parsed>> fields, Token first, Token last) {\n    // TODO: Get actual last token in all cases.\n    int endLine = (last == null) ? first.endLine : last.endLine;\n    int endColumn = (last == null) ? first.endColumn : last.endColumn;\n\n    // TODO: text is empty.\n    Source source = Source.fromString(\"\", first.beginLine, first.beginColumn, endLine, endColumn);\n\n    return new Expr.Parsed(Expr.makeUnionType((List) fields), source);\n  }\n\n  static final Expr.Parsed makeWith(Expr base, List<String> path, Expr.Parsed arg, Token first) {\n    // TODO: source isn't correct.\n    Source source = sourceFromToken(first);\n\n    return new Expr.Parsed(Expr.makeWith(base, path.toArray(new String[path.size()]), arg), source);\n  }\n\n  static final Expr.Parsed makeNonEmptyListLiteral(\n      List<Expr.Parsed> values, List<String> other, Token first, Token last) {\n    Source source =\n        new InterspersedSource(\n            other, values, first.beginLine, first.beginColumn, last.endLine, last.endColumn);\n    return new Expr.Parsed(\n        Expr.makeNonEmptyListLiteral(values.toArray(new Expr.Parsed[values.size()])), source);\n  }\n\n  static final Expr.Parsed makeEmptyListLiteral(Expr.Parsed tpe, String other, Token first) {\n    Source source = new SESource(other, tpe, first.beginLine, first.beginColumn);\n    return new Expr.Parsed(Expr.makeEmptyListLiteral(tpe), source);\n  }\n\n  static final Expr.Parsed makeParenthesized(Expr.Parsed value, Token first, Token last) {\n    Source source =\n        new SESSource(\n            \"(\", value, \")\", first.beginLine, first.beginColumn, last.endLine, last.endColumn);\n    return new Expr.Parsed(value, source);\n  }\n\n  static final Expr.Parsed makeImport(\n      Token type, Token hashToken, Token modeToken, Expr.Parsed using) {\n    // TODO: fix.\n    Source source = sourceFromToken(type);\n    byte[] hash =\n        (hashToken == null) ? null : Expr.Util.decodeHashBytes(hashToken.image.substring(7));\n    Expr value = null;\n    Expr.ImportMode mode =\n        (modeToken == null)\n            ? Expr.ImportMode.CODE\n            : (modeToken.image.equals(\"Text\")\n                ? Expr.ImportMode.RAW_TEXT\n                : Expr.ImportMode.LOCATION);\n\n    if (type.image.equals(\"missing\")) {\n      value = Expr.makeMissingImport(mode, hash);\n    } else if (type.image.startsWith(\"http\")) {\n      try {\n        value = Expr.makeRemoteImport(new URI(type.image), using, mode, hash);\n      } catch (java.net.URISyntaxException e) {\n        throw new ParsingFailure(\"Invalid URL\", e);\n      }\n    } else if (type.image.startsWith(\"env:\")) {\n      value = Expr.makeEnvImport(type.image.substring(4), mode, hash);\n    } else if (type.image.startsWith(\"classpath:\")) {\n      value = Expr.makeClasspathImport(Paths.get(type.image.substring(10)), mode, hash);\n    } else {\n      try {\n        value = Expr.makeLocalImport(Paths.get(type.image), mode, hash);\n      } catch (java.nio.file.InvalidPathException e) {\n        throw new ParsingFailure(\"Invalid path\", e);\n      }\n    }\n\n    return new Expr.Parsed(value, source);\n  }\n\n  private static final class ESESource extends Source {\n    private final Expr.Parsed i0;\n    private final String i1;\n    private final Expr.Parsed i2;\n\n    ESESource(Expr.Parsed i0, String i1, Expr.Parsed i2) {\n      super(\n          i0.getSource().getBeginLine(),\n          i0.getSource().getBeginColumn(),\n          i2.getSource().getEndLine(),\n          i2.getSource().getEndColumn());\n\n      this.i0 = i0;\n      this.i1 = i1;\n      this.i2 = i2;\n    }\n\n    public final void printText(StringBuilder builder) {\n      this.i0.getSource().printText(builder);\n      builder.append(this.i1);\n      this.i2.getSource().printText(builder);\n    }\n  }\n\n  private static final class ESSource extends Source {\n    private final Expr.Parsed i0;\n    private final String i1;\n\n    ESSource(Expr.Parsed i0, String i1, int endLine, int endColumn) {\n      super(i0.getSource().getBeginLine(), i0.getSource().getBeginColumn(), endLine, endColumn);\n      this.i0 = i0;\n      this.i1 = i1;\n    }\n\n    public final void printText(StringBuilder builder) {\n      this.i0.getSource().printText(builder);\n      builder.append(this.i1);\n    }\n  }\n\n  private static final class SESource extends Source {\n    private final String i0;\n    private final Expr.Parsed i1;\n\n    SESource(String i0, Expr.Parsed i1, int beginLine, int beginColumn) {\n      super(beginLine, beginColumn, i1.getSource().getEndLine(), i1.getSource().getEndColumn());\n      this.i0 = i0;\n      this.i1 = i1;\n    }\n\n    public final void printText(StringBuilder builder) {\n      builder.append(this.i0);\n      this.i1.getSource().printText(builder);\n    }\n  }\n\n  private static final class SESSource extends Source {\n    private final String i0;\n    private final Expr.Parsed i1;\n    private final String i2;\n\n    SESSource(\n        String i0,\n        Expr.Parsed i1,\n        String i2,\n        int beginLine,\n        int beginColumn,\n        int endLine,\n        int endColumn) {\n      super(beginLine, beginColumn, endLine, endColumn);\n      this.i0 = i0;\n      this.i1 = i1;\n      this.i2 = i2;\n    }\n\n    public final void printText(StringBuilder builder) {\n      builder.append(this.i0);\n      this.i1.getSource().printText(builder);\n      builder.append(this.i2);\n    }\n  }\n\n  private static final class SESESource extends Source {\n    private final String i0;\n    private final Expr.Parsed i1;\n    private final String i2;\n    private final Expr.Parsed i3;\n\n    SESESource(\n        String i0, Expr.Parsed i1, String i2, Expr.Parsed i3, int beginLine, int beginColumn) {\n      super(beginLine, beginColumn, i3.getSource().getEndLine(), i3.getSource().getEndColumn());\n      this.i0 = i0;\n      this.i1 = i1;\n      this.i2 = i2;\n      this.i3 = i3;\n    }\n\n    public final void printText(StringBuilder builder) {\n      builder.append(this.i0);\n      this.i1.getSource().printText(builder);\n      builder.append(this.i2);\n      this.i3.getSource().printText(builder);\n    }\n  }\n\n  private static final class SESESESource extends Source {\n    private final String i0;\n    private final Expr.Parsed i1;\n    private final String i2;\n    private final Expr.Parsed i3;\n    private final String i4;\n    private final Expr.Parsed i5;\n\n    SESESESource(\n        String i0,\n        Expr.Parsed i1,\n        String i2,\n        Expr.Parsed i3,\n        String i4,\n        Expr.Parsed i5,\n        int beginLine,\n        int beginColumn) {\n      super(beginLine, beginColumn, i5.getSource().getEndLine(), i5.getSource().getEndColumn());\n      this.i0 = i0;\n      this.i1 = i1;\n      this.i2 = i2;\n      this.i3 = i3;\n      this.i4 = i4;\n      this.i5 = i5;\n    }\n\n    public final void printText(StringBuilder builder) {\n      builder.append(this.i0);\n      this.i1.getSource().printText(builder);\n      builder.append(this.i2);\n      this.i3.getSource().printText(builder);\n      builder.append(this.i4);\n      this.i5.getSource().printText(builder);\n    }\n  }\n\n  private static final class InterspersedSource extends Source {\n    private final List<String> i0;\n    private final List<Expr.Parsed> i1;\n\n    InterspersedSource(\n        List<String> i0,\n        List<Expr.Parsed> i1,\n        int beginLine,\n        int beginColumn,\n        int endLine,\n        int endColumn) {\n      super(beginLine, beginColumn, endLine, endColumn);\n      this.i0 = i0;\n      this.i1 = i1;\n    }\n\n    public final void printText(StringBuilder builder) {\n      Iterator<String> ii0 = i0.iterator();\n      Iterator<Expr.Parsed> ii1 = i1.iterator();\n\n      while (ii0.hasNext() && ii1.hasNext()) {\n        builder.append(ii0.next());\n        ii1.next().getSource().printText(builder);\n      }\n\n      if (ii0.hasNext()) {\n        builder.append(ii0.next());\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/WhitespaceManager.java",
    "content": "package org.dhallj.parser.support;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Special tokenization for whitespace.\n *\n * <p>Dhall's definition of whitespace doesn't fit cleanly with JavaCC's model, so if we want no\n * consecutive whitespace tokens, we have to tokenize ourselves.\n *\n * <p>This is roughly working, except for the sources, but desperately needs clean-up.\n */\nfinal class WhitespaceManager {\n  private final List<Comment> comments = new ArrayList();\n  private char curr = 0;\n\n  private boolean advance(SimpleCharStream stream) {\n    try {\n      this.curr = stream.readChar();\n      return false;\n    } catch (IOException e) {\n      return true;\n    }\n  }\n\n  private void advanceNotEof(SimpleCharStream stream) {\n    if (advance(stream)) {\n      fail(this.curr, stream);\n    }\n  }\n\n  private static boolean isCommentChar(char c) {\n    return (c >= '\\u0020' && c <= '\\ud7ff') || (c >= '\\ue000' && c <= '\\ufffd') || (c == '\\t');\n  }\n\n  private static void fail(int current, SimpleCharStream stream) {\n    throw new TokenMgrException(\n        false,\n        0,\n        stream.getEndLine(),\n        stream.getEndColumn(),\n        stream.GetImage(),\n        current,\n        TokenMgrException.LEXICAL_ERROR);\n  }\n\n  List<Comment> consume(SimpleCharStream stream, char first) {\n    if (first == '{') {\n      return consumeWithComments(stream, true);\n    } else if (first == '-') {\n      return consumeWithComments(stream, false);\n    } else {\n      if (advance(stream)) {\n        return null;\n      } else if (this.curr == '{' || this.curr == '-') {\n        boolean startsWithBlock = this.curr == '{';\n        if (advance(stream)) {\n          stream.backup(1);\n          return null;\n        } else if (this.curr == '-') {\n          return consumeWithComments(stream, startsWithBlock);\n        } else {\n          stream.backup(2);\n          return null;\n        }\n      } else {\n        stream.backup(1);\n        return null;\n      }\n    }\n  }\n\n  private Comment consumeLineComment(SimpleCharStream stream) {\n    int commentLen = 2;\n    int commentBeginLine = stream.getBeginLine();\n    int commentBeginColumn = stream.getBeginColumn();\n\n    while (true) {\n      advanceNotEof(stream);\n\n      if (isCommentChar(this.curr)) {\n        commentLen += 1;\n      } else if (this.curr == '\\n') {\n        break;\n      } else if (this.curr == '\\r') {\n        if (advance(stream) || this.curr != '\\n') {\n          fail(this.curr, stream);\n        }\n        break;\n      } else if (Character.isHighSurrogate(this.curr)) {\n        if (advance(stream) || !Character.isLowSurrogate(this.curr)) {\n          fail(this.curr, stream);\n        }\n        commentLen += 2;\n      } else {\n        fail(this.curr, stream);\n      }\n    }\n\n    return new Comment(\n        new String(stream.GetSuffix(commentLen)),\n        commentBeginLine,\n        commentBeginColumn,\n        stream.getEndLine(),\n        stream.getEndColumn());\n  }\n\n  private Comment consumeBlockComment(SimpleCharStream stream) {\n    int blockCommentLevel = 1;\n    int commentLen = 2;\n    int commentBeginLine = stream.getBeginLine();\n    int commentBeginColumn = stream.getBeginColumn();\n\n    advanceNotEof(stream);\n\n    do {\n      if (this.curr == '-') {\n        advanceNotEof(stream);\n        if (this.curr == '}') {\n          blockCommentLevel -= 1;\n        } else {\n          commentLen += 1;\n          advanceNotEof(stream);\n        }\n      } else if (this.curr == '{') {\n        advanceNotEof(stream);\n        if (this.curr == '-') {\n          blockCommentLevel += 1;\n        } else {\n          commentLen += 1;\n          advanceNotEof(stream);\n        }\n      } else if (isCommentChar(this.curr) || this.curr == '\\n') {\n        commentLen += 1;\n        advanceNotEof(stream);\n      } else if (this.curr == '\\r') {\n        if (advance(stream) || this.curr != '\\n') {\n          fail(this.curr, stream);\n        }\n        commentLen += 1;\n        advanceNotEof(stream);\n      } else if (Character.isHighSurrogate(this.curr)) {\n        if (advance(stream) || !Character.isLowSurrogate(this.curr)) {\n          fail(this.curr, stream);\n        }\n        commentLen += 2;\n        advanceNotEof(stream);\n      } else {\n        fail(this.curr, stream);\n      }\n    } while (blockCommentLevel > 0);\n\n    return new Comment(\n        new String(stream.GetSuffix(commentLen)),\n        commentBeginLine,\n        commentBeginColumn,\n        stream.getEndLine(),\n        stream.getEndColumn());\n  }\n\n  private List<Comment> consumeWithComments(SimpleCharStream stream, boolean startsWithBlock) {\n    comments.clear();\n\n    if (startsWithBlock) {\n      comments.add(consumeBlockComment(stream));\n    } else {\n      comments.add(consumeLineComment(stream));\n    }\n\n    while (true) {\n      if (advance(stream)) {\n        return comments;\n      }\n\n      switch (this.curr) {\n        case ' ':\n        case '\\t':\n        case '\\n':\n          break;\n        case '{':\n          advance(stream);\n          if (this.curr == '-') {\n            comments.add(consumeBlockComment(stream));\n          } else {\n            stream.backup(2);\n            return comments;\n          }\n          break;\n        case '-':\n          advance(stream);\n          if (this.curr == '-') {\n            comments.add(consumeLineComment(stream));\n          } else {\n            stream.backup(2);\n            return comments;\n          }\n          break;\n        case '\\r':\n          advanceNotEof(stream);\n          if (this.curr != '\\n') {\n            stream.backup(2);\n            return comments;\n          }\n          break;\n        default:\n          stream.backup(1);\n          return null;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "modules/parser/src/main/java/org/dhallj/parser/support/package-info.java",
    "content": "/**\n * Support classes generated by JavaCC.\n *\n * <p>Please do not use the contents of this package directly!\n */\npackage org.dhallj.parser.support;\n"
  },
  {
    "path": "modules/parser/src/main/javacc/JavaCCParser.jj",
    "content": "options {\n  JDK_VERSION=\"1.8\";\n  JAVA_TEMPLATE_TYPE = \"modern\";\n  SUPPORT_CLASS_VISIBILITY_PUBLIC = false;\n  UNICODE_INPUT = true;\n  JAVA_UNICODE_ESCAPE = false;\n}\n\nPARSER_BEGIN(JavaCCParser)\n\npackage org.dhallj.parser.support;\n\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.Deque;\nimport java.util.List;\nimport java.util.Map;\nimport org.dhallj.core.Operator;\nimport org.dhallj.core.Expr;\n\nfinal class JavaCCParser {\n  private static final String trimLabel(String input) {\n    return (input.charAt(0) != '`') ? input : input.substring(1, input.length() - 1);\n  }\n}\n\nPARSER_END(JavaCCParser)\n\nTOKEN_MGR_DECLS : {\n  Deque<Boolean> interpolationState = new ArrayDeque<>();\n  Deque<Integer> braceDepth = new ArrayDeque<>();\n  List<Comment> comments = new ArrayList<>();\n  WhitespaceManager whitespace = new WhitespaceManager();\n}\n\nTOKEN: {\n    <WHSP: ([\" \", \"\\t\", \"\\n\"] | \"\\r\\n\")+ | \"{-\" | \"--\"> {\n      List<Comment> cs = whitespace.consume(input_stream, matchedToken.image.charAt(0));\n      if (cs != null) {\n        comments.addAll(cs);\n      }\n    }\n  | <DOUBLE_LITERAL: ((<SIGN>)? <DIGITS> ((\".\" <DIGITS> (<EXPONENT>)?) | <EXPONENT>)) | ((\"-\")? \"Infinity\") | \"NaN\">\n  | <INTEGER_LITERAL: <SIGN> <NATURAL_LITERAL>>\n  | <NATURAL_LITERAL: \"0\" | ([\"1\"-\"9\"] (<DIGIT>)*) | (\"0x\" <HEX_DIGITS>)>\n\n  | <IF: \"if\">\n  | <THEN: \"then\">\n  | <ELSE: \"else\">\n  | <LET: \"let\">\n  | <IN: \"in\">\n  | <AS: \"as\">\n  | <USING: \"using\">\n  | <MERGE: \"merge\">\n  | <MISSING: \"missing\">\n  | <SOME: \"Some\">\n  | <TOMAP: \"toMap\">\n  | <ASSERT: \"assert\">\n  | <FORALL: \"forall\" | \"∀\">\n  | <WITH: \"with\">\n  | <TEXT: \"Text\">\n  | <LOCATION: \"Location\">\n  | <BUILT_IN:\n      \"Natural/fold\"\n    | \"Natural/build\"\n    | \"Natural/isZero\"\n    | \"Natural/even\"\n    | \"Natural/odd\"\n    | \"Natural/toInteger\"\n    | \"Natural/show\"\n    | \"Integer/toDouble\"\n    | \"Integer/show\"\n    | \"Integer/negate\"\n    | \"Integer/clamp\"\n    | \"Natural/subtract\"\n    | \"Double/show\"\n    | \"List/build\"\n    | \"List/fold\"\n    | \"List/length\"\n    | \"List/head\"\n    | \"List/last\"\n    | \"List/indexed\"\n    | \"List/reverse\"\n    | \"Text/replace\"\n    | \"Text/show\"\n    | \"Bool\"\n    | \"True\"\n    | \"False\"\n    | \"None\"\n    | \"Natural\"\n    | \"Integer\"\n    | \"Double\"\n    | \"Text\"\n    | \"List\"\n    | \"Type\"\n    | \"Kind\"\n    | \"Sort\"\n    | \"Optional\"\n    | \"List\"\n    | \"Date\"\n    | \"Time\"\n    | \"TimeZone\"\n  >\n  | <QUOTED_LABEL: \"`\" ([\"\\u0020\"-\"\\u005f\"] | [\"\\u0061\"-\"\\u007e\"])* \"`\">\n  | <SIMPLE_LABEL: (<ALPHA> | \"_\") (<ALPHA> | <DIGIT> | \"_\" | \"-\" | \"/\" )*>\n  | <LAMBDA: \"\\\\\" | \"\\u03bb\">\n  | <ARROW: \"->\" | \"\\u2192\">\n  | <COMPLETE: \"::\">\n\n  | <OR: \"||\">\n  | <AND: \"&&\">\n  | <EQUALS: \"==\">\n  | <NOT_EQUALS: \"!=\">\n  | <PLUS: \"+\">\n  | <TIMES: \"*\">\n  | <TEXT_APPEND: \"++\">\n  | <LIST_APPEND: \"#\">\n  | <COMBINE: \"/\\\\\" | \"\\u2227\">\n  | <PREFER: \"//\" | \"\\u2afd\">\n  | <COMBINE_TYPES: \"//\\\\\\\\\" | \"\\u2a53\">\n  | <IMPORT_ALT: \"?\">\n  | <EQUIVALENT: \"===\" | \"\\u2261\">\n\n  | <DOUBLE_QUOTE_START: \"\\\"\">: WITHIN_DOUBLE_QUOTE\n  | <SINGLE_QUOTE_START: \"''\" (\"\\n\" | \"\\r\\n\")>: WITHIN_SINGLE_QUOTE\n  | <PARENS_OPEN: \"(\">\n  | <PARENS_CLOSE: \")\">\n  | <BRACKET_OPEN: \"[\">\n  | <BRACKET_CLOSE: \"]\">\n  | <BRACE_OPEN: \"{\"> { if (braceDepth.isEmpty()) { braceDepth.push(0); }; braceDepth.push(braceDepth.pop() + 1); ; }\n  | <BRACE_CLOSE: \"}\"> {\n    int currentBraceDepth = braceDepth.pop() - 1;\n    boolean currentInterpolationState = false;\n    if (currentBraceDepth >= 0) {\n      braceDepth.push(currentBraceDepth);\n    } else {\n      currentInterpolationState = interpolationState.pop();\n    }\n    SwitchTo((currentBraceDepth >= 0)\n      ? DEFAULT\n      : (currentInterpolationState) ? WITHIN_DOUBLE_QUOTE : WITHIN_SINGLE_QUOTE);\n  }\n  | <ANGLE_OPEN: \"<\">\n  | <ANGLE_CLOSE: \">\">\n  | <DOT: \".\">\n  | <COLON: \":\">\n  | <COMMA: \",\">\n  | <BAR: \"|\">\n  | <EQUAL_SIGN: \"=\">\n  | <AT_SIGN: \"@\">\n  | <SHA256_HASH: \"sha256:\" (<HEX_DIGIT>){64}>\n  | <ENV: \"env:\" (<BASH_ENV_VAR> | (\"\\\"\" <POSIX_ENV_VAR> \"\\\"\"))>\n  | <HTTP: \"http\" (\"s\")? \"://\" (<USER_INFO> \"@\")? <HOST> (\":\" (<DIGIT>)*)? <URL_PATH> (\"?\" <QUERY>)?>\n  | <LOCAL: <PARENT_PATH> | <HERE_PATH> | <HOME_PATH> | <PATH>>\n  | <CLASSPATH: \"classpath:\" <PATH> >\n  | <#DIGIT: [\"0\"-\"9\"]>\n  | <#DIGIT2: <DIGIT> <DIGIT>>\n  | <#DIGIT4: <DIGIT> <DIGIT> <DIGIT> <DIGIT>>\n  | <#DIGITS: (<DIGIT>)+>\n  | <#HEX_DIGIT: <DIGIT> | [\"A\"-\"F\"] | [\"a\"-\"f\"]>\n  | <#HEX_DIGITS: (<HEX_DIGIT>)+>\n  | <#SIGN: \"+\" | \"-\">\n  | <#EXPONENT: (\"E\" | \"e\") (<SIGN>)? <DIGITS>>\n  | <#ALPHA: [\"A\"-\"Z\"] | [\"a\"-\"z\"]>\n  | <#ASCII: [\"\\u0020\"-\"\\u007f\"]>\n  | <#VALID_NON_ASCII: [\"\\u0080\"-\"\\uD7FF\"] | ([\"\\ud800\"-\"\\udbff\"] [\"\\udc00\"-\"\\udfff\"]) | [\"\\ue000\"-\"\\ufffd\"]>\n  | <#BASH_ENV_VAR: (<ALPHA> | \"_\") (<ALPHA> | <DIGIT> | \"_\")*>\n  | <#POSIX_ENV_VAR: (\"\\u0020\" | \"\\u0021\" | [\"\\u0023\"-\"\\u003c\"] | [\"\\u003e\"-\"\\u005b\"] | [\"\\u005d\"-\"\\u007e\"] | (\"\\\\\" ([\"\\\"\", \"\\\\\", \"a\", \"b\", \"f\", \"n\", \"r\", \"t\", \"v\"])))+>\n\n  | <#PCT_ENCODED: \"%\" <HEX_DIGIT> <HEX_DIGIT>>\n  | <#SUB_DELIM: [\"!\", \"$\", \"&\", \"'\", \"*\", \"+\", \";\", \"=\"]>\n  | <#UNRESERVED: <ALPHA> | <DIGIT> | [\"-\", \".\", \"_\", \"~\"]>\n  | <#PCHAR: <UNRESERVED> | <PCT_ENCODED> | <SUB_DELIM> | \":\" | \"@\">\n  | <#SEGMENT: (<PCHAR>)*>\n  | <#USER_INFO: (<UNRESERVED> | <PCT_ENCODED> | <SUB_DELIM> | \":\")*>\n  | <#QUERY: (<PCHAR> | \"/\" | \"?\")*>\n  | <#DOMAIN_LABEL: (<ALPHA> | <DIGIT>)+ ((\"-\")+ (<ALPHA> | <DIGIT>)+)*>\n  | <#DOMAIN: <DOMAIN_LABEL> (\".\" <DOMAIN_LABEL>)* (\".\")?>\n  | <#IPV4: <DEC_OCTET> \".\" <DEC_OCTET> \".\" <DEC_OCTET> \".\" <DEC_OCTET>>\n  | <#H16: (<HEX_DIGIT>){1,4}>\n  | <#LS32: (<H16> \":\" <H16>) | <IPV4>>\n  | <#IPV6:\n      ((<H16> \":\"){6} <LS32>)\n    | (\"::\" (<H16> \":\"){5} <LS32>)\n    | ((<H16>)? \"::\" (<H16> \":\"){4} <LS32>)\n    | ((<H16> (\":\" <H16>){0, 1})? \"::\" (<H16> \":\"){3} <LS32>)\n    | ((<H16> (\":\" <H16>){0, 2})? \"::\" (<H16> \":\"){2} <LS32>)\n    | ((<H16> (\":\" <H16>){0, 3})? \"::\" <H16> \":\" <LS32>)\n    | ((<H16> (\":\" <H16>){0, 4})? \"::\" <LS32>)\n    | ((<H16> (\":\" <H16>){0, 5})? \"::\" <H16>)\n    | ((<H16> (\":\" <H16>){0, 6})? \"::\")\n    >\n  | <#IPVFUTURE: \"v\" (<HEX_DIGIT>)+ \".\" (<UNRESERVED> | <SUB_DELIM> | \":\")+>\n  | <#DEC_OCTET: (\"25\" [\"0\"-\"5\"]) | (\"2\" [\"0\"-\"4\"] <DIGIT>) | (\"1\" <DIGIT2>) | ([\"1\"-\"9\"] <DIGIT>) | <DIGIT>>\n  | <#HOST: <DOMAIN> | <IPV4> | (\"[\" (<IPV6> | <IPVFUTURE>) \"]\")>\n  | <#PATH_CHARACTER:\n      [\"\\u0021\", \"\\u003d\", \"\\u007c\", \"\\u007e\"]\n    | [\"\\u0024\"-\"\\u0027\"] | [\"\\u002a\"-\"\\u002b\"] | [\"\\u002d\"-\"\\u002e\"]\n    | [\"\\u0030\"-\"\\u003b\"] | [\"\\u0040\"-\"\\u005a\"] | [\"\\u0040\"-\"\\u005a\"] | [\"\\u005e\"-\"\\u007a\"]>\n  | <#QUOTED_PATH_CHARACTER: [\"\\u0020\"-\"\\u0021\"] | [\"\\u0023\"-\"\\u002e\"] | [\"\\u0030\"-\"\\u007f\"] | <VALID_NON_ASCII>>\n  | <#PATH_COMPONENT: \"/\" ((<PATH_CHARACTER>)+ | (\"\\\"\" (<QUOTED_PATH_CHARACTER>)+ \"\\\"\"))>\n  | <#URL_PATH_COMPONENT: \"/\" ((<PATH_CHARACTER>)+)>\n  | <#PATH: (<PATH_COMPONENT>)+>\n  | <#PARENT_PATH: \"..\" <PATH>>\n  | <#HERE_PATH: \".\" <PATH>>\n  | <#HOME_PATH: \"~\" <PATH>>\n  | <#URL_PATH: (<URL_PATH_COMPONENT> | (\"/\") <SEGMENT>)*>\n  | <SHEBANG: \"#!\" (<ASCII> | <VALID_NON_ASCII> | \"\\t\")+ (\"\\n\" | \"\\r\\n\")>\n  | <TIME_NUMOFFSET: (\"+\" | \"-\") <DIGIT2> \":\" <DIGIT2>>\n  | <FULL_DATE: <DIGIT4> \"-\" <DIGIT2> \"-\" <DIGIT2>>\n  | <PARTIAL_TIME: <DIGIT2> \":\" <DIGIT2> \":\" <DIGIT2> (\".\" (<DIGIT>)+)?>\n  | <DATE_TIME: <FULL_DATE> (\"T\" | \"t\") <PARTIAL_TIME>>\n}\n\n<WITHIN_DOUBLE_QUOTE> TOKEN: {\n  <DOUBLE_QUOTE_INTERPOLATION: \"${\"> {\n    interpolationState.push(true);\n    braceDepth.push(0);\n    SwitchTo(DEFAULT);\n  } |\n  <DOUBLE_QUOTE_DOLLAR_SIGN: \"$\"> |\n  <DOUBLE_QUOTE_CHARS: (\n      \"\\u0020\" | \"\\u0021\" | \"#\" | [\"\\u0025\"-\"\\u005b\"] | [\"\\u005d\"-\"\\u007f\"]\n    | (\"\\\\\" ([\"\\\"\", \"$\", \"\\\\\", \"/\", \"b\", \"f\", \"n\", \"r\", \"t\"]))\n    | (\"\\\\u\" <UNICODE_ESCAPE>)\n    | <VALID_NON_ASCII>\n  )+> |\n  <#UNICODE_ESCAPE: <UNBRACED_ESCAPE> | (\"{\" <BRACED_ESCAPE> \"}\")> |\n  <#UNBRACED_ESCAPE:\n      ((<DIGIT> | \"A\" | \"B\" | \"C\" | \"a\" | \"b\" | \"c\") (<HEX_DIGIT>){3})\n    | ((\"D\" | \"d\") [\"0\"-\"7\"] <HEX_DIGIT> <HEX_DIGIT>)\n    | ((\"E\" | \"e\") (<HEX_DIGIT>){3})\n    | ((\"F\" | \"f\") <HEX_DIGIT> <HEX_DIGIT> (\"A\" | \"B\" | \"C\" | \"D\" | \"a\" | \"b\" | \"c\" | \"d\"))\n  > |\n  <#BRACED_ESCAPE: (\"0\")* <BRACED_CODEPOINT>> |\n  <#BRACED_CODEPOINT: (([\"0\"-\"9\"] | [\"A\"-\"F\"] | [\"a\"-\"f\"] | \"10\") <UNICODE_SUFFIX>) | <UNBRACED_ESCAPE> | (<HEX_DIGIT>){3}> |\n  <#UNICODE_SUFFIX: ((<DIGIT> | [\"A\"-\"E\"] | [\"a\"-\"e\"]) (<HEX_DIGIT>){3}) | ((\"F\" | \"f\") <HEX_DIGIT> <HEX_DIGIT> (<DIGIT> | [\"A\"-\"D\"] | [\"a\"-\"d\"]))>\n}\n<WITHIN_DOUBLE_QUOTE> TOKEN: { <DOUBLE_QUOTE_END: \"\\\"\">: DEFAULT }\n\n<WITHIN_SINGLE_QUOTE> TOKEN: {\n  <SINGLE_QUOTE_INTERPOLATION: \"${\"> {\n    interpolationState.push(false);\n    braceDepth.push(0);\n    SwitchTo(DEFAULT);\n  } |\n  <ESCAPED_QUOTE_PAIR: \"'''\"> |\n  <ESCAPED_INTERPOLATION: \"''${\"> |\n  <SINGLE_QUOTE_CHARS: (<ASCII> | <VALID_NON_ASCII> | \"\\t\" | \"\\n\" | \"\\r\\n\")>\n}\n<WITHIN_SINGLE_QUOTE> TOKEN: { <SINGLE_QUOTE_END: \"''\">: DEFAULT }\n\nString ANY_LABEL_OR_SOME(): { Token token; } {\n  (token=<SIMPLE_LABEL> | token=<QUOTED_LABEL> | token=<TEXT> | token=<LOCATION> | token=<BUILT_IN> | token=<SOME>) {\n    return trimLabel(token.image);\n  }\n}\n\nString NAME_BINDING(): { Token token; } {\n  (token=<SIMPLE_LABEL> | token=<QUOTED_LABEL> | token=<TEXT> | token=<LOCATION>) {\n    return trimLabel(token.image);\n  }\n}\n\nMap.Entry<String, Expr.Parsed> DOUBLE_QUOTE_CHUNK(): {\n  StringBuilder builder = null;\n  Token token0 = null;\n  Token token1 = null;\n  Expr.Parsed expr = null;\n} {\n  (\n      (<DOUBLE_QUOTE_INTERPOLATION> expr=COMPLETE_EXPRESSION() <BRACE_CLOSE>)\n    | (\n      (token0=<DOUBLE_QUOTE_DOLLAR_SIGN> | token0=<DOUBLE_QUOTE_CHARS>)\n      (LOOKAHEAD(2)\n        (token1=<DOUBLE_QUOTE_DOLLAR_SIGN> | token1=<DOUBLE_QUOTE_CHARS>) {\n          if (builder == null) {\n            builder = new StringBuilder(token0.image);\n          }\n          builder.append(token1.image);\n        }\n      )*\n    )\n  ) {\n    if (builder == null) {\n      return new SimpleImmutableEntry<>(token0 == null ? null : token0.image, expr);\n    } else {\n      return new SimpleImmutableEntry<>(builder.toString(), expr);\n    }\n  }\n}\n\nExpr.Parsed DOUBLE_QUOTE_LITERAL(): {\n  List<Map.Entry<String, Expr.Parsed>> chunks = new ArrayList<>(1);\n  Map.Entry<String, Expr.Parsed> current;\n  Token first;\n  Token last;\n} {\n  first=<DOUBLE_QUOTE_START>\n  (current=DOUBLE_QUOTE_CHUNK() { chunks.add(current); })*\n  last=<DOUBLE_QUOTE_END> {\n    return ParsingHelpers.makeTextLiteral(chunks, first, last);\n  }\n}\n\nList<Map.Entry<String, Expr.Parsed>> SINGLE_QUOTE_CONTINUE(): {\n  List<Map.Entry<String, Expr.Parsed>> continuation = null;\n  Token token = null;\n  Expr.Parsed expr = null;\n} {\n\n    (\n      <SINGLE_QUOTE_INTERPOLATION> expr=COMPLETE_EXPRESSION() <BRACE_CLOSE> continuation=SINGLE_QUOTE_CONTINUE()\n    | token=<ESCAPED_QUOTE_PAIR> continuation=SINGLE_QUOTE_CONTINUE()\n    | token=<ESCAPED_INTERPOLATION> continuation=SINGLE_QUOTE_CONTINUE()\n    | token=<SINGLE_QUOTE_CHARS> continuation=SINGLE_QUOTE_CONTINUE()\n    | <SINGLE_QUOTE_END>\n    ) {\n      if (continuation == null) {\n        return new ArrayList<Map.Entry<String, Expr.Parsed>>();\n      } else {\n        String value = null;\n\n        if (token != null) {\n          value = token.image;\n\n          if (value.equals(\"'''\")) {\n            value = \"''\";\n          } else if (value.equals(\"''${\")) {\n            value = \"${\";\n          }\n        }\n\n        continuation.add(new SimpleImmutableEntry<>(value, expr));\n        return continuation;\n      }\n    }\n}\n\nExpr.Parsed SINGLE_QUOTE_LITERAL(): {\n  List<Map.Entry<String, Expr.Parsed>> chunks;\n  Token first;\n} {\n  (\n    first=<SINGLE_QUOTE_START> chunks=SINGLE_QUOTE_CONTINUE()\n  ) {\n    return ParsingHelpers.makeSingleQuotedTextLiteral(chunks, first);\n  }\n}\n\nExpr.Parsed IDENTIFIER(): {\n  Token value;\n  Token whsp0 = null;\n  Token whsp1 = null;\n  Token index = null;\n} {\n  (\n      (\n        (value=<QUOTED_LABEL> | value=<SIMPLE_LABEL>)\n        (\n          LOOKAHEAD(2)\n          [whsp0=<WHSP>] <AT_SIGN>\n          [whsp1=<WHSP>]\n          index=<NATURAL_LITERAL>\n        )?\n      )\n    | value=<BUILT_IN>\n    | value=<TEXT>\n    | value=<LOCATION>\n  ) {\n    return (index == null)\n      ? ParsingHelpers.makeBuiltInOrIdentifier(value)\n      : ParsingHelpers.makeIdentifier(value, whsp0, whsp1, index);\n  }\n}\n\nExpr.Parsed NON_EMPTY_LIST_LITERAL(): {\n  Token first;\n  Token last;\n  Token t0 = null;\n  Token t1 = null;\n  Token t2 = null;\n  List<String> other = new ArrayList<>();\n  StringBuilder currentOther = new StringBuilder(\"[\");\n  List<Expr.Parsed> values = new ArrayList<>();\n  Expr.Parsed current;\n} {\n  (\n    first=<BRACKET_OPEN>\n    (t0=<WHSP> { currentOther.append(t0.image); })?\n    (t0=<COMMA> { currentOther.append(t0.image); } (t0=<WHSP> { currentOther.append(t0.image); })?)?\n    current=BASE_EXPRESSION() {\n      values.add(current);\n      other.add(currentOther.toString());\n      currentOther.setLength(0);\n    }\n    (t0=<WHSP> { currentOther.append(t0.image); })?\n    (\n      t0=<COMMA> { currentOther.append(t0.image); }\n      (t0=<WHSP> { currentOther.append(t0.image); })?\n      (\n        current=BASE_EXPRESSION() {\n          values.add(current);\n          other.add(currentOther.toString());\n          currentOther.setLength(0);\n        }\n        (t0=<WHSP> { currentOther.append(t0.image); })?\n      )?\n    )*\n    last=<BRACKET_CLOSE>\n  ) {\n    currentOther.append(']');\n    other.add(currentOther.toString());\n    return ParsingHelpers.makeNonEmptyListLiteral(values, other, first, last);\n  }\n}\n\n\nList<Map.Entry<List<String>, Expr.Parsed>> RECORD_LITERAL_ENTRY(String firstLabel): {\n  List<Map.Entry<List<String>, Expr.Parsed>> values = new ArrayList<>();\n  List<Map.Entry<List<String>, Expr.Parsed>> next = null;\n  List<String> current = new ArrayList<>();\n  current.add(firstLabel);\n  Expr.Parsed expr;\n} {\n  (\n    (\n      (\n        (\n          <EQUAL_SIGN> |\n          ((<DOT> [<WHSP>] firstLabel=ANY_LABEL_OR_SOME() { current.add(firstLabel); })+ [<WHSP>] <EQUAL_SIGN>)\n        )\n        [<WHSP>]\n        expr=BASE_EXPRESSION() {\n          values.add(new SimpleImmutableEntry<>(current, expr));\n          current = new ArrayList<>();\n        }\n        [<WHSP>]\n      ) |\n      ({} { values.add(new SimpleImmutableEntry<List<String>, Expr.Parsed>(current, null)); current = new ArrayList<>(); })\n    )\n      (\n        <COMMA>\n        [<WHSP>]\n        (\n          firstLabel=ANY_LABEL_OR_SOME() { current.add(firstLabel); }\n          [<WHSP>]\n          (\n            (\n              (\n                <EQUAL_SIGN> |\n                ((<DOT> [<WHSP>] firstLabel=ANY_LABEL_OR_SOME() { current.add(firstLabel); })+ [<WHSP>] <EQUAL_SIGN>)\n              )\n              [<WHSP>]\n              expr=BASE_EXPRESSION() {\n                values.add(new SimpleImmutableEntry<>(current, expr));\n                current = new ArrayList<>();\n              }\n              [<WHSP>]\n            ) |\n            ({} { values.add(new SimpleImmutableEntry<List<String>, Expr.Parsed>(current, null)); current = new ArrayList<>(); })\n          )\n        )?\n      )*\n      <BRACE_CLOSE>\n  ) {\n    return values;\n  }\n}\n\nList<Map.Entry<String, Expr.Parsed>> RECORD_TYPE_ENTRY(String firstLabel): {\n  List<Map.Entry<String, Expr.Parsed>> values = new ArrayList<>();\n  List<Map.Entry<String, Expr.Parsed>> next = null;\n  Expr.Parsed expr;\n} {\n  (\n    <COLON> <WHSP>\n    expr=BASE_EXPRESSION() { values.add(new SimpleImmutableEntry<>(firstLabel, expr)); }\n    [<WHSP>]\n    (\n      <COMMA>\n      [<WHSP>]\n      (\n        firstLabel=ANY_LABEL_OR_SOME()\n        [<WHSP>] <COLON> <WHSP>\n        expr=BASE_EXPRESSION() { values.add(new SimpleImmutableEntry<>(firstLabel, expr)); }\n        [<WHSP>]\n      )?\n    )*\n    <BRACE_CLOSE>\n  ) {\n    return values;\n  }\n}\n\nExpr.Parsed RECORD_LITERAL_OR_TYPE(): {\n  Token first;\n  Token last = null;\n  String firstLabel = null;\n  List<Map.Entry<List<String>, Expr.Parsed>> literalValues = null;\n  List<Map.Entry<String, Expr.Parsed>> typeValues = null;\n} {\n  (\n    first=<BRACE_OPEN>\n    [<WHSP>]\n    (<COMMA> [<WHSP>])?\n    (\n        last=<BRACE_CLOSE>\n      | (<EQUAL_SIGN> [<WHSP>] [<COMMA> [<WHSP>]] last=<BRACE_CLOSE> { literalValues = new ArrayList<>(); })\n      | (\n        firstLabel=ANY_LABEL_OR_SOME()\n        [<WHSP>]\n        (typeValues=RECORD_TYPE_ENTRY(firstLabel) | literalValues=RECORD_LITERAL_ENTRY(firstLabel))\n      )\n    )\n  ) {\n    if (literalValues != null) {\n      return ParsingHelpers.makeRecordLiteral(literalValues, first, last);\n    } else if (typeValues != null) {\n      return ParsingHelpers.makeRecordType(typeValues, first, last);\n    } else {\n      return ParsingHelpers.makeRecordType(new ArrayList<Map.Entry<String, Expr.Parsed>>(), first, last);\n    }\n  }\n}\n\nExpr.Parsed UNION_TYPE(): {\n  Token first;\n  Token last;\n  String label;\n  Expr.Parsed type = null;\n  List<Map.Entry<String, Expr.Parsed>> typeValues = new ArrayList<>();\n} {\n  (\n    first=<ANGLE_OPEN>\n    [<WHSP>]\n    [<BAR> [<WHSP>]]\n    (\n        last=<ANGLE_CLOSE>\n      | (\n        (\n          label=ANY_LABEL_OR_SOME()\n          [<WHSP>]\n          (\n            [<COLON> <WHSP> type=BASE_EXPRESSION() [<WHSP>]] {\n              typeValues.add(new SimpleImmutableEntry<>(label, type));\n              type = null;\n            }\n            (\n              <BAR>\n              [<WHSP>]\n              (\n                label=ANY_LABEL_OR_SOME()\n                [<WHSP>]\n                [<COLON> <WHSP> type=BASE_EXPRESSION() [<WHSP>]] {\n                  typeValues.add(new SimpleImmutableEntry<>(label, type));\n                  type = null;\n                }\n              )?\n            )*\n          )\n        )\n        last=<ANGLE_CLOSE>\n      )\n    )\n  ) {\n    return ParsingHelpers.makeUnionType(typeValues, first, last);\n  }\n}\n\nExpr.Parsed PARENTHESIZED_EXPRESSION(): {\n  Expr.Parsed value;\n  Token first;\n  Token last;\n} {\n  (first=<PARENS_OPEN> value=COMPLETE_EXPRESSION() last=<PARENS_CLOSE>) {\n    return ParsingHelpers.makeParenthesized(value, first, last);\n  }\n}\n\nExpr.Parsed DOUBLE_LITERAL():  { Token token; } { token=<DOUBLE_LITERAL>  { return ParsingHelpers.makeDoubleLiteral(token);  }}\nExpr.Parsed INTEGER_LITERAL(): { Token token; } { token=<INTEGER_LITERAL> { return ParsingHelpers.makeIntegerLiteral(token); }}\nExpr.Parsed NATURAL_LITERAL(): { Token token; } { token=<NATURAL_LITERAL> { return ParsingHelpers.makeNaturalLiteral(token); }}\n\nExpr.Parsed DATE_LITERAL(): { Token token; } { token=<FULL_DATE> { return ParsingHelpers.makeDateLiteral(token); }}\nExpr.Parsed TIME_ZONE_LITERAL(): { Token token; } { token=<TIME_NUMOFFSET> { return ParsingHelpers.makeTimeZoneLiteral(token); }}\nExpr.Parsed TIME_LITERAL(): {\n  Token token;\n  Token timeZone = null;\n} {\n  (token=<PARTIAL_TIME> [(timeZone=<TIME_NUMOFFSET>) | (timeZone=<SIMPLE_LABEL>)]) {\n    // Matching the \"Z\" in this way is a little convoluted but seems necessary to work around generated code size limits.\n    return ParsingHelpers.makeTimeLiteral(token, timeZone);\n  }\n}\n\nExpr.Parsed DATE_TIME_LITERAL(): {\n  Token token;\n  Token timeZone = null;\n} {\n  (token=<DATE_TIME> [(timeZone=<TIME_NUMOFFSET>) | (timeZone=<SIMPLE_LABEL>)]) {\n    // Matching the \"Z\" in this way is a little convoluted but seems necessary to work around generated code size limits.\n    return ParsingHelpers.makeDateTimeLiteral(token, timeZone);\n  }\n}\n\nExpr.Parsed TEMPORAL_LITERAL(): { Expr.Parsed expr; } {\n  (\n      expr=DATE_LITERAL()\n    | expr=TIME_ZONE_LITERAL()\n    | expr=TIME_LITERAL()\n    | expr=DATE_TIME_LITERAL()\n  ) { return expr; }\n}\n\nExpr.Parsed PRIMITIVE_EXPRESSION(): { Expr.Parsed expr; } {\n  (\n      expr=DOUBLE_LITERAL()\n    | expr=NATURAL_LITERAL()\n    | expr=INTEGER_LITERAL()\n    | expr=TEMPORAL_LITERAL()\n    | expr=DOUBLE_QUOTE_LITERAL()\n    | expr=SINGLE_QUOTE_LITERAL()\n    | expr=RECORD_LITERAL_OR_TYPE()\n    | expr=UNION_TYPE()\n    | expr=NON_EMPTY_LIST_LITERAL()\n    | expr=IDENTIFIER()\n    | expr=PARENTHESIZED_EXPRESSION()\n  ) { return expr; }\n}\n\nExpr.Parsed FIELD_ACCESS_EXPRESSION(Expr.Parsed base, Token whsp0, Token whsp1): {\n  Token token;\n} {\n  (token=<SIMPLE_LABEL> | token=<QUOTED_LABEL> | token=<TEXT> | token=<LOCATION> | token=<BUILT_IN>) {\n    return ParsingHelpers.makeFieldAccess(base, trimLabel(token.image), whsp0, whsp1, token.endLine, token.endColumn);\n  }\n}\n\nExpr.Parsed PROJECTION_EXPRESSION(Expr.Parsed base, Token whsp0, Token whsp): {\n  String current;\n  List<String> labels = new ArrayList<String>();\n  Token last;\n} {\n  (\n    <BRACE_OPEN> [<WHSP>] [<COMMA> [<WHSP>]]\n    (\n      current=ANY_LABEL_OR_SOME() { labels.add(current); }\n      [<WHSP>]\n      (<COMMA> [<WHSP>] (current=ANY_LABEL_OR_SOME() { labels.add(current); } [<WHSP>])?)*\n    )?\n    last=<BRACE_CLOSE>\n  ) {\n    return ParsingHelpers.makeProjection(base, labels, last.endLine, last.endColumn);\n  }\n}\n\nExpr.Parsed PROJECTION_BY_TYPE_EXPRESSION(Expr.Parsed base, Token whsp0, Token whsp): {\n  Expr.Parsed expr;\n  Token last;\n} {\n  (<PARENS_OPEN> [<WHSP>] expr=BASE_EXPRESSION() [<WHSP>] last=<PARENS_CLOSE>) {\n    return ParsingHelpers.makeProjectionByType(base, expr, last.endLine, last.endColumn);\n  }\n}\n\nExpr.Parsed SELECTOR_EXPRESSION(): {\n  Expr.Parsed base;\n  Token whsp0 = null;\n  Token whsp1 = null;\n} {\n  (\n    base=PRIMITIVE_EXPRESSION()\n    (\n      LOOKAHEAD(2)\n      [whsp0=<WHSP>] <DOT> [whsp1=<WHSP>]\n      (\n        base=FIELD_ACCESS_EXPRESSION(base, whsp0, whsp1)\n      | base=PROJECTION_EXPRESSION(base, whsp0, whsp1)\n      | base=PROJECTION_BY_TYPE_EXPRESSION(base, whsp0, whsp1)\n      ) {\n        whsp0 = null;\n        whsp1 = null;\n      }\n    )*\n  ) {\n    return base;\n  }\n}\n\nExpr.Parsed COMPLETION_EXPRESSION(): {\n  Expr.Parsed base;\n  Expr.Parsed completion = null;\n  Token operatorToken;\n  Token whsp0 = null;\n  Token whsp1 = null;\n} {\n  (\n    base=SELECTOR_EXPRESSION()\n    (\n      LOOKAHEAD(2)\n      [whsp0=<WHSP>] operatorToken=<COMPLETE> [whsp1=<WHSP>]\n      completion=SELECTOR_EXPRESSION() {\n        base = ParsingHelpers.makeOperatorApplication(Operator.COMPLETE, base, completion, operatorToken.image, whsp0, whsp1);\n      }\n    )?\n  ) {\n    return base;\n  }\n}\n\nExpr.Parsed IMPORT(): {\n  Token token = null;\n  Token hash = null;\n  Token asValue = null;\n  Expr.Parsed using = null;\n} {\n  (\n    (\n        token=<MISSING>\n      | token=<LOCAL>\n      | (token=<HTTP> (LOOKAHEAD(2) [<WHSP>] <USING> <WHSP> using=IMPORT_EXPRESSION())?)\n      | token=<ENV>\n      | token=<CLASSPATH>\n    )\n    (LOOKAHEAD(2) <WHSP> hash=<SHA256_HASH>)?\n    (LOOKAHEAD(2) [<WHSP>] <AS> <WHSP> (asValue=<TEXT> | asValue=<LOCATION>))?\n  ) {\n    return ParsingHelpers.makeImport(token, hash, asValue, using);\n  }\n}\n\nExpr.Parsed IMPORT_EXPRESSION(): { Expr.Parsed expr; } {\n  (expr=IMPORT() | expr=COMPLETION_EXPRESSION()) { return expr; }\n}\n\nExpr.Parsed APPLICATION_EXPRESSION(): {\n  Token first = null;\n  Token whsp0;\n  Token whsp1;\n  Expr.Parsed base = null;\n  Expr.Parsed current0;\n  Expr.Parsed current1;\n  Token whsp2 = null;\n  Token whsp3 = null;\n  Expr.Parsed expr;\n  Expr.Parsed other;\n  Expr.Parsed type = null;\n} {\n  (\n    (\n      (first=<MERGE>\n      whsp0=<WHSP>\n      expr=IMPORT_EXPRESSION()\n      whsp1=<WHSP>\n      other=IMPORT_EXPRESSION()\n      (LOOKAHEAD(2)\n        [whsp2=<WHSP>]\n        <COLON>\n        whsp3=<WHSP>\n        type=BASE_EXPRESSION()\n      )?) {\n        base = ParsingHelpers.makeMerge(expr, other, type, first, whsp0, whsp1, whsp2, whsp3);\n      }\n      |\n      (first=<SOME> whsp0=<WHSP> current0=IMPORT_EXPRESSION() { base = ParsingHelpers.makeApplication(ParsingHelpers.makeBuiltInOrIdentifier(first), current0, whsp0); })\n      |\n      (first=<TOMAP>\n      whsp0=<WHSP>\n      expr=IMPORT_EXPRESSION()\n      (LOOKAHEAD(2)\n        [whsp2=<WHSP>]\n        <COLON>\n        whsp3=<WHSP>\n        type=BASE_EXPRESSION()\n      )?) {\n          base = ParsingHelpers.makeToMap(expr, type, first, whsp0, whsp2, whsp3);\n      }\n      | base=IMPORT_EXPRESSION()\n    ) (\n      LOOKAHEAD(2)\n      whsp0=<WHSP> current0=IMPORT_EXPRESSION() { base = ParsingHelpers.makeApplication(base, current0, whsp0); }\n    )*\n  ) {\n    return base;\n  }\n}\n\nMap.Entry<String, Operator> OPERATOR(): {\n  Token token;\n  Token whsp = null;\n  Operator operator;\n} {\n  (\n      token=<OR> { operator = Operator.OR; }\n    | token=<AND> { operator = Operator.AND; }\n    | token=<EQUALS> { operator = Operator.EQUALS; }\n    | token=<NOT_EQUALS> { operator = Operator.NOT_EQUALS; }\n    | (token=<PLUS> whsp=<WHSP>) { operator = Operator.PLUS; }\n    | token=<TIMES> { operator = Operator.TIMES; }\n    | token=<TEXT_APPEND> { operator = Operator.TEXT_APPEND; }\n    | token=<LIST_APPEND> { operator = Operator.LIST_APPEND; }\n    | token=<COMBINE> { operator = Operator.COMBINE; }\n    | token=<PREFER> { operator = Operator.PREFER; }\n    | token=<COMBINE_TYPES> { operator = Operator.COMBINE_TYPES; }\n    | (token=<IMPORT_ALT> whsp=<WHSP>) { operator = Operator.IMPORT_ALT; }\n    | token=<EQUIVALENT> { operator = Operator.EQUIVALENT; }\n  ) {\n    if (whsp == null) {\n      return new SimpleImmutableEntry<>(token.image, operator);\n    } else {\n      return new SimpleImmutableEntry<>(token.image + whsp.image, operator);\n    }\n  }\n}\n\nExpr.Parsed OPERATOR_EXPRESSION(int minPredecence): {\n  Expr.Parsed base;\n  Expr.Parsed arg;\n  Map.Entry<String, Operator> operator;\n  Map.Entry<List<String>, Expr.Parsed> current;\n  Token whsp0 = null;\n  Token whsp1 = null;\n} {\n  (\n    base=APPLICATION_EXPRESSION()\n    (LOOKAHEAD({\n      getToken(1).kind == WHSP && getToken(2).kind == WITH && minPredecence < 1\n    })\n      whsp0=<WHSP> <WITH> <WHSP>\n      current=WITH_ENTRY() { base = ParsingHelpers.makeWith(base, current.getKey(), current.getValue(), whsp0); }\n    )*\n    (LOOKAHEAD({\n      (getToken(1).kind == WHSP && OperatorPrecedenceTable.get(getToken(2).kind) >= minPredecence) ||\n      OperatorPrecedenceTable.get(getToken(1).kind) >= minPredecence\n    })\n    [whsp0=<WHSP>]\n    operator=OPERATOR() [whsp1=<WHSP>] arg=OPERATOR_EXPRESSION(operator.getValue().getPrecedence() + 1) {\n      base = ParsingHelpers.makeOperatorApplication(operator.getValue(), base, arg, operator.getKey(), whsp0, whsp1);\n      whsp0 = null;\n    })*\n  ) {\n    return base;\n  }\n}\n\nMap.Entry<List<String>, Expr.Parsed> WITH_ENTRY(): {\n  List<String> labels = new ArrayList<String>();\n  String current;\n  Expr.Parsed expr;\n} {\n  (\n    current=ANY_LABEL_OR_SOME() { labels.add(current); }\n    (LOOKAHEAD(2) [<WHSP>] <DOT> [<WHSP>] current=ANY_LABEL_OR_SOME() { labels.add(current); })*\n    [<WHSP>]\n    <EQUAL_SIGN>\n    [<WHSP>]\n    expr=OPERATOR_EXPRESSION(1)\n  ) {\n    return new SimpleImmutableEntry<>(labels, expr);\n  }\n}\n\nExpr.Parsed EMPTY_LIST_LITERAL(): {\n  Expr.Parsed type;\n  Token first;\n  Token t0;\n  StringBuilder builder = new StringBuilder(\"[\");\n} {\n  (\n    first=<BRACKET_OPEN>\n    (t0=<WHSP> { builder.append(t0.image); })?\n    (<COMMA> { builder.append(','); } (t0=<WHSP> { builder.append(t0.image); })?)?\n    <BRACKET_CLOSE> { builder.append(']'); }\n    (t0=<WHSP> { builder.append(t0.image); })?\n    <COLON>\n    t0=<WHSP> {\n      builder.append(':');\n      builder.append(t0.image);\n    }\n    type=BASE_EXPRESSION()\n  ) {\n    return ParsingHelpers.makeEmptyListLiteral(type, builder.toString(), first);\n  }\n}\n\nExpr.Parsed LAMBDA_EXPRESSION(): {\n  Expr.Parsed type;\n  Expr.Parsed body;\n  Token first;\n  String name;\n} {\n  (\n    first=<LAMBDA> [<WHSP>] <PARENS_OPEN> [<WHSP>]\n    name=NAME_BINDING() [<WHSP>] <COLON> <WHSP>\n    type=BASE_EXPRESSION() [<WHSP>] <PARENS_CLOSE> [<WHSP>] <ARROW> [<WHSP>]\n    body=BASE_EXPRESSION()\n  ) {\n    return ParsingHelpers.makeLambda(name, type, body, first);\n  }\n}\n\nLetBinding LET_BINDING(): {\n  Token first;\n  Token whsp;\n  String name;\n  Expr.Parsed type = null;\n  Expr.Parsed value;\n  StringBuilder builder = new StringBuilder();\n  String text0 = null;\n  String text2 = null;\n} {\n  (\n    first=<LET>\n    whsp=<WHSP>\n    name=NAME_BINDING() {\n      builder.append(first.image);\n      builder.append(whsp.image);\n      builder.append(name);\n    }\n    (whsp=<WHSP> { builder.append(whsp.image); })?\n    (\n      <COLON> whsp=<WHSP> {\n        builder.append(':');\n        builder.append(whsp.image);\n        text0 = builder.toString();\n        builder.setLength(0);\n      }\n      type=BASE_EXPRESSION()\n      (whsp=<WHSP> { builder.append(whsp.image); })?\n    )?\n    <EQUAL_SIGN> { builder.append('='); }\n    (whsp=<WHSP> { builder.append(whsp.image); })?\n    value=BASE_EXPRESSION()\n    (whsp=<WHSP> { text2 = whsp.image; })?\n  ) {\n    return new LetBinding(name, type, value, text0, builder.toString(), text2, first.beginLine, first.beginColumn);\n  }\n}\n\nExpr.Parsed LET_EXPRESSION(): {\n  LetBinding current = null;\n  List<LetBinding> bindings = new ArrayList<>();\n  Expr.Parsed body;\n  Token whsp;\n} {\n  (\n    (current=LET_BINDING() { bindings.add(current); })+ <IN> whsp=<WHSP> body=BASE_EXPRESSION()\n  ) {\n    return ParsingHelpers.makeLet(bindings, body, whsp.image);\n  }\n}\n\nExpr.Parsed IF_EXPRESSION(): {\n  Token first;\n  Expr.Parsed predicate;\n  Expr.Parsed thenValue;\n  Expr.Parsed elseValue;\n} {\n  (\n    first=<IF> <WHSP> predicate=BASE_EXPRESSION() [<WHSP>] <THEN> <WHSP> thenValue=BASE_EXPRESSION() [<WHSP>] <ELSE> <WHSP> elseValue=BASE_EXPRESSION()\n  ) {\n    return ParsingHelpers.makeIf(predicate, thenValue, elseValue, first);\n  }\n}\n\nExpr.Parsed FORALL_EXPRESSION(): {\n  Token first;\n  String name;\n  Expr.Parsed input;\n  Expr.Parsed result;\n} {\n  (\n    first=<FORALL> [<WHSP>] <PARENS_OPEN> [<WHSP>]\n    name=NAME_BINDING() [<WHSP>] <COLON> <WHSP>\n    input=BASE_EXPRESSION() [<WHSP>] <PARENS_CLOSE> [<WHSP>] <ARROW> [<WHSP>]\n    result=BASE_EXPRESSION()\n  ) {\n    return ParsingHelpers.makePi(name, input, result, first);\n  }\n}\n\nExpr.Parsed ASSERT_EXPRESSION(): {\n  Token first;\n  Token whsp0 = null;\n  Token whsp1 = null;\n  Expr.Parsed value;\n} {\n  (first=<ASSERT> [whsp0=<WHSP>] <COLON> whsp1=<WHSP> value=BASE_EXPRESSION()) {\n    return ParsingHelpers.makeAssert(value, first, whsp0, whsp1);\n  }\n}\n\nExpr.Parsed FUNCTION_TYPE_OR_ANNOTATED_EXPRESSION(): {\n  Expr.Parsed base;\n  Expr.Parsed type = null;\n  Expr.Parsed result = null;\n  Token whsp0 = null;\n  Token whsp1 = null;\n} {\n  (\n    base=OPERATOR_EXPRESSION(0)\n    (LOOKAHEAD(2)\n      [whsp0=<WHSP>]\n      ((<ARROW> [<WHSP>] result=BASE_EXPRESSION()) |\n      (<COLON> whsp1=<WHSP> type=BASE_EXPRESSION()))\n    )?\n  ) {\n    if (type == null) {\n      if (result == null) {\n        return base;\n      } else {\n        return ParsingHelpers.makePi(base, result);\n      }\n    } else {\n      return ParsingHelpers.makeAnnotated(base, type, whsp0, whsp1);\n    }\n  }\n}\n\nExpr.Parsed BASE_EXPRESSION(): { Expr.Parsed expr; } {\n  (\n      expr=LAMBDA_EXPRESSION()\n    | expr=IF_EXPRESSION()\n    | expr=LET_EXPRESSION()\n    | expr=FORALL_EXPRESSION()\n    | LOOKAHEAD(EMPTY_LIST_LITERAL()) expr=EMPTY_LIST_LITERAL()\n    | expr=ASSERT_EXPRESSION()\n    | expr=FUNCTION_TYPE_OR_ANNOTATED_EXPRESSION()\n  ) {\n    return expr;\n  }\n}\n\nExpr.Parsed COMPLETE_EXPRESSION(): { Expr.Parsed expr; } { ([<WHSP>] expr=BASE_EXPRESSION() [<WHSP>]) { return expr; }}\n\nExpr.Parsed TOP_LEVEL(): { Expr.Parsed expr; } { ((<SHEBANG>)* expr=COMPLETE_EXPRESSION() <EOF>) { return expr; }}\n"
  },
  {
    "path": "modules/parser/src/test/scala/org/dhallj/parser/DhallParserSuite.scala",
    "content": "package org.dhallj.parser\n\nimport java.net.URI\nimport java.io.FileInputStream\nimport java.nio.charset.StandardCharsets\nimport java.nio.file.Paths\n\nimport munit.{FunSuite, Ignore}\nimport org.dhallj.core.DhallException.ParsingFailure\nimport org.dhallj.core.Expr\nimport org.dhallj.core.Expr.ImportMode\n\nclass DhallParserSuite extends FunSuite() {\n  test(\"parse empty list with annotation on element type\") {\n    val expected = Expr.makeEmptyListLiteral(\n      Expr.makeAnnotated(Expr.makeApplication(Expr.Constants.LIST, Expr.Constants.NATURAL), Expr.Constants.TYPE)\n    )\n    // Output from dhall-haskell.\n    val expectedBytes: Array[Byte] = Array(-126, 24, 28, -125, 24, 26, -125, 0, 100, 76, 105, 115, 116, 103, 78, 97,\n                                           116, 117, 114, 97, 108, 100, 84, 121, 112, 101)\n    val parsed = DhallParser.parse(\"[]: List Natural: Type\")\n\n    assert(parsed == expected)\n    assert(parsed.getEncodedBytes.sameElements(expectedBytes))\n  }\n\n  test(\"parse toMap with empty record with annotation on type\") {\n    // Output from dhall-haskell.\n    val expectedBytes: Array[Byte] = Array(-125, 24, 27, -126, 7, -96, -125, 24, 26, -125, 0, 100, 76, 105, 115, 116,\n                                           -126, 7, -94, 102, 109, 97, 112, 75, 101, 121, 100, 84, 101, 120, 116, 104,\n                                           109, 97, 112, 86, 97, 108, 117, 101, 100, 66, 111, 111, 108, 100, 84, 121,\n                                           112, 101)\n    val parsed = DhallParser.parse(\"toMap {}: List { mapKey : Text, mapValue: Bool }: Type\")\n\n    assert(parsed.getEncodedBytes.sameElements(expectedBytes))\n  }\n\n  test(\"parse toMap with empty non-record with annotation on type\") {\n    // Output from dhall-haskell.\n    val expectedBytes: Array[Byte] = Array(-125, 24, 27, -126, 8, -95, 97, 97, -11, -125, 24, 26, -125, 0, 100, 76, 105,\n                                           115, 116, -126, 7, -94, 102, 109, 97, 112, 75, 101, 121, 100, 84, 101, 120,\n                                           116, 104, 109, 97, 112, 86, 97, 108, 117, 101, 100, 66, 111, 111, 108, 100,\n                                           84, 121, 112, 101)\n    val parsed = DhallParser.parse(\"toMap {a=True}: List { mapKey : Text, mapValue: Bool }: Type\")\n\n    assert(parsed.getEncodedBytes.sameElements(expectedBytes))\n  }\n\n  test(\"parse merge with annotation on type\") {\n    // Output from dhall-haskell.\n    val expectedBytes: Array[Byte] =\n      Array(-124, 6, -126, 8, -95, 97, 97, -126, 15, 1, -125, 9, -126, 11, -95, 97, 97, -10, 97, 97, -125, 24, 26, 103,\n            78, 97, 116, 117, 114, 97, 108, 100, 84, 121, 112, 101)\n    val parsed = DhallParser.parse(\"merge {a=1} <a>.a: Natural: Type\")\n\n    assert(parsed.getEncodedBytes.sameElements(expectedBytes))\n  }\n\n  test(\"parse IPv6 address\") {\n    val expected = Expr.makeRemoteImport(new URI(\"https://[0:0:0:0:0:0:0:1]/\"), null, Expr.ImportMode.CODE, null)\n\n    assert(DhallParser.parse(\"https://[0:0:0:0:0:0:0:1]/\") == expected)\n  }\n\n  test(\"parse $ in double-quoted text literals\") {\n    val expected = Expr.makeTextLiteral(\"$ $ $100 $ $\")\n\n    assert(DhallParser.parse(\"\"\"let x = \"100\" in \"$ $ $${x} $ $\" \"\"\") == expected)\n  }\n\n  test(\"parse # in double-quoted text literals\") {\n    val expected = Expr.makeTextLiteral(\"# # # $ % ^ #\")\n\n    assert(DhallParser.parse(\"\"\"\"# # # $ % ^ #\"\"\"\") == expected)\n  }\n\n  test(\"parse classpath import\") {\n    val expected = Expr.makeClasspathImport(Paths.get(\"/foo/bar.dhall\"), ImportMode.RAW_TEXT, null)\n\n    assert(DhallParser.parse(\"classpath:/foo/bar.dhall as Text\") == expected)\n  }\n\n  test(\"fail on URLs with quoted paths\") {\n    intercept[ParsingFailure](DhallParser.parse(\"https://example.com/foo/\\\"bar?baz\\\"?qux\"))\n  }\n\n  test(\"fail on non-UTF-8 input\") {\n    val stream = new FileInputStream(\"dhall-lang/tests/parser/failure/nonUtf8.dhall\")\n\n    intercept[ParsingFailure](DhallParser.parse(stream, StandardCharsets.UTF_16))\n  }\n\n  test(\"handle single-quoted escape sequences\") {\n    val expected = Expr.makeTextLiteral(\"foo '' bar ${ baz '''' qux\")\n\n    val input = \"\"\"''\nfoo ''' bar ''${ baz '''''' qux''\"\"\"\n\n    assertEquals(DhallParser.parse(input): Expr, expected)\n\n  }\n}\n"
  },
  {
    "path": "modules/prelude/src/main/java/org/dhallj/prelude/Prelude.java",
    "content": "package org.dhallj.prelude;\n\nimport java.math.BigInteger;\nimport java.util.AbstractMap.SimpleImmutableEntry;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.Operator;\n\npublic final class Prelude {\n  private static final Expr f000000 = Expr.makeBuiltIn(\"List/fold\");\n  private static final Expr f000001 = Expr.makeBuiltIn(\"Bool\");\n  private static final Expr f000002 = Expr.makeIdentifier(\"xs\", 0);\n  private static final Expr f000003 = Expr.makeIdentifier(\"l\", 0);\n  private static final Expr f000004 = Expr.makeIdentifier(\"r\", 0);\n  private static final Expr f000005 = Expr.makeOperatorApplication(Operator.AND, f000003, f000004);\n  private static final Expr f000006 = Expr.makeLambda(\"r\", f000001, f000005);\n  private static final Expr f000007 = Expr.makeLambda(\"l\", f000001, f000006);\n  private static final Expr f000008 = Expr.Constants.TRUE;\n  private static final Expr f000009 =\n      Expr.makeApplication(f000000, new Expr[] {f000001, f000002, f000001, f000007, f000008});\n  private static final Expr f000010 = Expr.Constants.LIST;\n  private static final Expr f000011 = Expr.makeApplication(f000010, new Expr[] {f000001});\n  private static final Expr f000012 = Expr.makeLambda(\"xs\", f000011, f000009);\n  private static final Expr f000013 = Expr.makeIdentifier(\"f\", 0);\n  private static final Expr f000014 = Expr.Constants.FALSE;\n  private static final Expr f000015 =\n      Expr.makeApplication(f000013, new Expr[] {f000001, f000008, f000014});\n  private static final Expr f000016 = Expr.makeIdentifier(\"bool\", 0);\n  private static final Expr f000017 = Expr.makePi(\"false\", f000016, f000016);\n  private static final Expr f000018 = Expr.makePi(\"true\", f000016, f000017);\n  private static final Expr f000019 = Expr.Constants.TYPE;\n  private static final Expr f000020 = Expr.makePi(\"bool\", f000019, f000018);\n  private static final Expr f000021 = Expr.makeLambda(\"f\", f000020, f000015);\n  private static final Expr f000022 = Expr.makeIdentifier(\"x\", 0);\n  private static final Expr f000023 = Expr.makeIdentifier(\"y\", 0);\n  private static final Expr f000024 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000022, f000023);\n  private static final Expr f000025 = Expr.makeLambda(\"y\", f000001, f000024);\n  private static final Expr f000026 = Expr.makeLambda(\"x\", f000001, f000025);\n  private static final Expr f000027 =\n      Expr.makeApplication(f000000, new Expr[] {f000001, f000002, f000001, f000026, f000008});\n  private static final Expr f000028 = Expr.makeLambda(\"xs\", f000011, f000027);\n  private static final Expr f000029 = Expr.makeIdentifier(\"b\", 0);\n  private static final Expr f000030 = Expr.makeIdentifier(\"true\", 0);\n  private static final Expr f000031 = Expr.makeIdentifier(\"false\", 0);\n  private static final Expr f000032 = Expr.makeIf(f000029, f000030, f000031);\n  private static final Expr f000033 = Expr.makeLambda(\"false\", f000016, f000032);\n  private static final Expr f000034 = Expr.makeLambda(\"true\", f000016, f000033);\n  private static final Expr f000035 = Expr.makeLambda(\"bool\", f000019, f000034);\n  private static final Expr f000036 = Expr.makeLambda(\"b\", f000001, f000035);\n  private static final Expr f000037 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000029, f000014);\n  private static final Expr f000038 = Expr.makeLambda(\"b\", f000001, f000037);\n  private static final Expr f000039 =\n      Expr.makeOperatorApplication(Operator.NOT_EQUALS, f000022, f000023);\n  private static final Expr f000040 = Expr.makeLambda(\"y\", f000001, f000039);\n  private static final Expr f000041 = Expr.makeLambda(\"x\", f000001, f000040);\n  private static final Expr f000042 =\n      Expr.makeApplication(f000000, new Expr[] {f000001, f000002, f000001, f000041, f000014});\n  private static final Expr f000043 = Expr.makeLambda(\"xs\", f000011, f000042);\n  private static final Expr f000044 = Expr.makeOperatorApplication(Operator.OR, f000003, f000004);\n  private static final Expr f000045 = Expr.makeLambda(\"r\", f000001, f000044);\n  private static final Expr f000046 = Expr.makeLambda(\"l\", f000001, f000045);\n  private static final Expr f000047 =\n      Expr.makeApplication(f000000, new Expr[] {f000001, f000002, f000001, f000046, f000014});\n  private static final Expr f000048 = Expr.makeLambda(\"xs\", f000011, f000047);\n  private static final Expr f000049 = Expr.makeTextLiteral(\"True\");\n  private static final Expr f000050 = Expr.makeTextLiteral(\"False\");\n  private static final Expr f000051 = Expr.makeIf(f000029, f000049, f000050);\n  private static final Expr f000052 = Expr.makeLambda(\"b\", f000001, f000051);\n  private static final Expr f000053 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"and\", f000012),\n            new SimpleImmutableEntry<String, Expr>(\"build\", f000021),\n            new SimpleImmutableEntry<String, Expr>(\"even\", f000028),\n            new SimpleImmutableEntry<String, Expr>(\"fold\", f000036),\n            new SimpleImmutableEntry<String, Expr>(\"not\", f000038),\n            new SimpleImmutableEntry<String, Expr>(\"odd\", f000043),\n            new SimpleImmutableEntry<String, Expr>(\"or\", f000048),\n            new SimpleImmutableEntry<String, Expr>(\"show\", f000052)\n          });\n  private static final Expr f000054 = Expr.makeBuiltIn(\"Double/show\");\n  private static final Expr f000055 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"show\", f000054)});\n  private static final Expr f000056 = Expr.makeIdentifier(\"g\", 0);\n  private static final Expr f000057 = Expr.makeApplication(f000013, new Expr[] {f000022});\n  private static final Expr f000058 = Expr.makeApplication(f000056, new Expr[] {f000057});\n  private static final Expr f000059 = Expr.makeIdentifier(\"A\", 0);\n  private static final Expr f000060 = Expr.makeLambda(\"x\", f000059, f000058);\n  private static final Expr f000061 = Expr.makeIdentifier(\"C\", 0);\n  private static final Expr f000062 = Expr.makeIdentifier(\"B\", 0);\n  private static final Expr f000063 = Expr.makePi(\"_\", f000062, f000061);\n  private static final Expr f000064 = Expr.makeLambda(\"g\", f000063, f000060);\n  private static final Expr f000065 = Expr.makePi(\"_\", f000059, f000062);\n  private static final Expr f000066 = Expr.makeLambda(\"f\", f000065, f000064);\n  private static final Expr f000067 = Expr.makeLambda(\"C\", f000019, f000066);\n  private static final Expr f000068 = Expr.makeLambda(\"B\", f000019, f000067);\n  private static final Expr f000069 = Expr.makeLambda(\"A\", f000019, f000068);\n  private static final Expr f000070 = Expr.makeIdentifier(\"a\", 0);\n  private static final Expr f000071 = Expr.makeLambda(\"x\", f000070, f000022);\n  private static final Expr f000072 = Expr.makeLambda(\"a\", f000019, f000071);\n  private static final Expr f000073 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"compose\", f000069),\n            new SimpleImmutableEntry<String, Expr>(\"identity\", f000072)\n          });\n  private static final Expr f000074 = Expr.makeBuiltIn(\"Natural/isZero\");\n  private static final Expr f000075 = Expr.makeBuiltIn(\"Integer/clamp\");\n  private static final Expr f000076 = Expr.makeIdentifier(\"n\", 0);\n  private static final Expr f000077 = Expr.makeApplication(f000075, new Expr[] {f000076});\n  private static final Expr f000078 = Expr.makeApplication(f000074, new Expr[] {f000077});\n  private static final Expr f000079 = Expr.makeBuiltIn(\"Integer/negate\");\n  private static final Expr f000080 = Expr.makeApplication(f000079, new Expr[] {f000076});\n  private static final Expr f000081 = Expr.makeApplication(f000075, new Expr[] {f000080});\n  private static final Expr f000082 = Expr.makeIf(f000078, f000081, f000077);\n  private static final Expr f000083 = Expr.Constants.INTEGER;\n  private static final Expr f000084 = Expr.makeLambda(\"n\", f000083, f000082);\n  private static final Expr f000085 = Expr.makeIdentifier(\"m\", 0);\n  private static final Expr f000086 = Expr.makeApplication(f000079, new Expr[] {f000085});\n  private static final Expr f000087 = Expr.makeApplication(f000075, new Expr[] {f000086});\n  private static final Expr f000088 = Expr.makeApplication(f000074, new Expr[] {f000087});\n  private static final Expr f000089 = Expr.makeBuiltIn(\"Natural/subtract\");\n  private static final Expr f000090 = Expr.makeApplication(f000079, new Expr[] {f000086});\n  private static final Expr f000091 = Expr.makeApplication(f000075, new Expr[] {f000090});\n  private static final Expr f000092 = Expr.makeApplication(f000089, new Expr[] {f000081, f000091});\n  private static final Expr f000093 = Expr.makeApplication(f000074, new Expr[] {f000092});\n  private static final Expr f000094 = Expr.makeBuiltIn(\"Natural/toInteger\");\n  private static final Expr f000095 = Expr.makeApplication(f000089, new Expr[] {f000091, f000081});\n  private static final Expr f000096 = Expr.makeApplication(f000094, new Expr[] {f000095});\n  private static final Expr f000097 = Expr.makeApplication(f000079, new Expr[] {f000096});\n  private static final Expr f000098 = Expr.makeApplication(f000094, new Expr[] {f000092});\n  private static final Expr f000099 = Expr.makeIf(f000093, f000097, f000098);\n  private static final Expr f000100 = Expr.makeOperatorApplication(Operator.PLUS, f000091, f000077);\n  private static final Expr f000101 = Expr.makeApplication(f000094, new Expr[] {f000100});\n  private static final Expr f000102 = Expr.makeIf(f000078, f000099, f000101);\n  private static final Expr f000103 = Expr.makeOperatorApplication(Operator.PLUS, f000087, f000081);\n  private static final Expr f000104 = Expr.makeApplication(f000094, new Expr[] {f000103});\n  private static final Expr f000105 = Expr.makeApplication(f000079, new Expr[] {f000104});\n  private static final Expr f000106 = Expr.makeApplication(f000089, new Expr[] {f000087, f000077});\n  private static final Expr f000107 = Expr.makeApplication(f000074, new Expr[] {f000106});\n  private static final Expr f000108 = Expr.makeApplication(f000089, new Expr[] {f000077, f000087});\n  private static final Expr f000109 = Expr.makeApplication(f000094, new Expr[] {f000108});\n  private static final Expr f000110 = Expr.makeApplication(f000079, new Expr[] {f000109});\n  private static final Expr f000111 = Expr.makeApplication(f000094, new Expr[] {f000106});\n  private static final Expr f000112 = Expr.makeIf(f000107, f000110, f000111);\n  private static final Expr f000113 = Expr.makeIf(f000078, f000105, f000112);\n  private static final Expr f000114 = Expr.makeIf(f000088, f000102, f000113);\n  private static final Expr f000115 = Expr.makeLambda(\"n\", f000083, f000114);\n  private static final Expr f000116 = Expr.makeLambda(\"m\", f000083, f000115);\n  private static final Expr f000117 = Expr.makeApplication(f000075, new Expr[] {f000029});\n  private static final Expr f000118 = Expr.makeApplication(f000075, new Expr[] {f000070});\n  private static final Expr f000119 = Expr.makeApplication(f000089, new Expr[] {f000117, f000118});\n  private static final Expr f000120 = Expr.makeApplication(f000074, new Expr[] {f000119});\n  private static final Expr f000121 = Expr.makeApplication(f000089, new Expr[] {f000118, f000117});\n  private static final Expr f000122 = Expr.makeApplication(f000074, new Expr[] {f000121});\n  private static final Expr f000123 = Expr.makeOperatorApplication(Operator.AND, f000120, f000122);\n  private static final Expr f000124 = Expr.makeApplication(f000079, new Expr[] {f000029});\n  private static final Expr f000125 = Expr.makeApplication(f000075, new Expr[] {f000124});\n  private static final Expr f000126 = Expr.makeApplication(f000079, new Expr[] {f000070});\n  private static final Expr f000127 = Expr.makeApplication(f000075, new Expr[] {f000126});\n  private static final Expr f000128 = Expr.makeApplication(f000089, new Expr[] {f000125, f000127});\n  private static final Expr f000129 = Expr.makeApplication(f000074, new Expr[] {f000128});\n  private static final Expr f000130 = Expr.makeApplication(f000089, new Expr[] {f000127, f000125});\n  private static final Expr f000131 = Expr.makeApplication(f000074, new Expr[] {f000130});\n  private static final Expr f000132 = Expr.makeOperatorApplication(Operator.AND, f000129, f000131);\n  private static final Expr f000133 = Expr.makeOperatorApplication(Operator.AND, f000123, f000132);\n  private static final Expr f000134 = Expr.makeLambda(\"b\", f000083, f000133);\n  private static final Expr f000135 = Expr.makeLambda(\"a\", f000083, f000134);\n  private static final Expr f000136 = Expr.makeApplication(f000075, new Expr[] {f000022});\n  private static final Expr f000137 = Expr.makeApplication(f000074, new Expr[] {f000136});\n  private static final Expr f000138 = Expr.makeApplication(f000079, new Expr[] {f000023});\n  private static final Expr f000139 = Expr.makeApplication(f000075, new Expr[] {f000138});\n  private static final Expr f000140 = Expr.makeApplication(f000074, new Expr[] {f000139});\n  private static final Expr f000141 = Expr.makeApplication(f000079, new Expr[] {f000022});\n  private static final Expr f000142 = Expr.makeApplication(f000075, new Expr[] {f000141});\n  private static final Expr f000143 = Expr.makeApplication(f000089, new Expr[] {f000142, f000139});\n  private static final Expr f000144 = Expr.makeApplication(f000074, new Expr[] {f000143});\n  private static final Expr f000145 = Expr.makeOperatorApplication(Operator.OR, f000140, f000144);\n  private static final Expr f000146 = Expr.makeApplication(f000075, new Expr[] {f000023});\n  private static final Expr f000147 = Expr.makeApplication(f000089, new Expr[] {f000146, f000136});\n  private static final Expr f000148 = Expr.makeApplication(f000074, new Expr[] {f000147});\n  private static final Expr f000149 = Expr.makeIf(f000137, f000145, f000148);\n  private static final Expr f000150 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000149, f000014);\n  private static final Expr f000151 = Expr.makeLambda(\"y\", f000083, f000150);\n  private static final Expr f000152 = Expr.makeLambda(\"x\", f000083, f000151);\n  private static final Expr f000153 = Expr.makeApplication(f000074, new Expr[] {f000146});\n  private static final Expr f000154 = Expr.makeApplication(f000074, new Expr[] {f000142});\n  private static final Expr f000155 = Expr.makeApplication(f000089, new Expr[] {f000139, f000142});\n  private static final Expr f000156 = Expr.makeApplication(f000074, new Expr[] {f000155});\n  private static final Expr f000157 = Expr.makeOperatorApplication(Operator.OR, f000154, f000156);\n  private static final Expr f000158 = Expr.makeApplication(f000089, new Expr[] {f000136, f000146});\n  private static final Expr f000159 = Expr.makeApplication(f000074, new Expr[] {f000158});\n  private static final Expr f000160 = Expr.makeIf(f000153, f000157, f000159);\n  private static final Expr f000161 = Expr.makeLambda(\"y\", f000083, f000160);\n  private static final Expr f000162 = Expr.makeLambda(\"x\", f000083, f000161);\n  private static final Expr f000163 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000160, f000014);\n  private static final Expr f000164 = Expr.makeLambda(\"y\", f000083, f000163);\n  private static final Expr f000165 = Expr.makeLambda(\"x\", f000083, f000164);\n  private static final Expr f000166 = Expr.makeLambda(\"y\", f000083, f000149);\n  private static final Expr f000167 = Expr.makeLambda(\"x\", f000083, f000166);\n  private static final Expr f000168 = Expr.makeApplication(f000075, new Expr[] {f000085});\n  private static final Expr f000169 = Expr.makeApplication(f000074, new Expr[] {f000168});\n  private static final Expr f000170 =\n      Expr.makeOperatorApplication(Operator.TIMES, f000087, f000081);\n  private static final Expr f000171 = Expr.makeApplication(f000094, new Expr[] {f000170});\n  private static final Expr f000172 =\n      Expr.makeOperatorApplication(Operator.TIMES, f000087, f000077);\n  private static final Expr f000173 = Expr.makeApplication(f000094, new Expr[] {f000172});\n  private static final Expr f000174 = Expr.makeApplication(f000079, new Expr[] {f000173});\n  private static final Expr f000175 = Expr.makeIf(f000078, f000171, f000174);\n  private static final Expr f000176 =\n      Expr.makeOperatorApplication(Operator.TIMES, f000168, f000081);\n  private static final Expr f000177 = Expr.makeApplication(f000094, new Expr[] {f000176});\n  private static final Expr f000178 = Expr.makeApplication(f000079, new Expr[] {f000177});\n  private static final Expr f000179 =\n      Expr.makeOperatorApplication(Operator.TIMES, f000168, f000077);\n  private static final Expr f000180 = Expr.makeApplication(f000094, new Expr[] {f000179});\n  private static final Expr f000181 = Expr.makeIf(f000078, f000178, f000180);\n  private static final Expr f000182 = Expr.makeIf(f000169, f000175, f000181);\n  private static final Expr f000183 = Expr.makeLambda(\"n\", f000083, f000182);\n  private static final Expr f000184 = Expr.makeLambda(\"m\", f000083, f000183);\n  private static final Expr f000185 = Expr.makeApplication(f000074, new Expr[] {f000081});\n  private static final Expr f000186 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000185, f000014);\n  private static final Expr f000187 = Expr.makeLambda(\"n\", f000083, f000186);\n  private static final Expr f000188 = Expr.makeLambda(\"n\", f000083, f000185);\n  private static final Expr f000189 = Expr.makeLambda(\"n\", f000083, f000078);\n  private static final Expr f000190 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000078, f000014);\n  private static final Expr f000191 = Expr.makeLambda(\"n\", f000083, f000190);\n  private static final Expr f000192 = Expr.makeBuiltIn(\"Integer/show\");\n  private static final Expr f000193 = Expr.makeApplication(f000089, new Expr[] {f000081, f000087});\n  private static final Expr f000194 = Expr.makeApplication(f000074, new Expr[] {f000193});\n  private static final Expr f000195 = Expr.makeApplication(f000089, new Expr[] {f000087, f000081});\n  private static final Expr f000196 = Expr.makeApplication(f000094, new Expr[] {f000195});\n  private static final Expr f000197 = Expr.makeApplication(f000079, new Expr[] {f000196});\n  private static final Expr f000198 = Expr.makeApplication(f000094, new Expr[] {f000193});\n  private static final Expr f000199 = Expr.makeIf(f000194, f000197, f000198);\n  private static final Expr f000200 = Expr.makeOperatorApplication(Operator.PLUS, f000087, f000077);\n  private static final Expr f000201 = Expr.makeApplication(f000094, new Expr[] {f000200});\n  private static final Expr f000202 = Expr.makeIf(f000078, f000199, f000201);\n  private static final Expr f000203 = Expr.makeOperatorApplication(Operator.PLUS, f000168, f000081);\n  private static final Expr f000204 = Expr.makeApplication(f000094, new Expr[] {f000203});\n  private static final Expr f000205 = Expr.makeApplication(f000079, new Expr[] {f000204});\n  private static final Expr f000206 = Expr.makeApplication(f000089, new Expr[] {f000168, f000077});\n  private static final Expr f000207 = Expr.makeApplication(f000074, new Expr[] {f000206});\n  private static final Expr f000208 = Expr.makeApplication(f000089, new Expr[] {f000077, f000168});\n  private static final Expr f000209 = Expr.makeApplication(f000094, new Expr[] {f000208});\n  private static final Expr f000210 = Expr.makeApplication(f000079, new Expr[] {f000209});\n  private static final Expr f000211 = Expr.makeApplication(f000094, new Expr[] {f000206});\n  private static final Expr f000212 = Expr.makeIf(f000207, f000210, f000211);\n  private static final Expr f000213 = Expr.makeIf(f000078, f000205, f000212);\n  private static final Expr f000214 = Expr.makeIf(f000169, f000202, f000213);\n  private static final Expr f000215 = Expr.makeLambda(\"n\", f000083, f000214);\n  private static final Expr f000216 = Expr.makeLambda(\"m\", f000083, f000215);\n  private static final Expr f000217 = Expr.makeBuiltIn(\"Integer/toDouble\");\n  private static final Expr f000218 = Expr.makeBuiltIn(\"Some\");\n  private static final Expr f000219 = Expr.makeApplication(f000218, new Expr[] {f000077});\n  private static final Expr f000220 = Expr.makeBuiltIn(\"None\");\n  private static final Expr f000221 = Expr.Constants.NATURAL;\n  private static final Expr f000222 = Expr.makeApplication(f000220, new Expr[] {f000221});\n  private static final Expr f000223 = Expr.makeIf(f000185, f000219, f000222);\n  private static final Expr f000224 = Expr.makeLambda(\"n\", f000083, f000223);\n  private static final Expr f000225 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"abs\", f000084),\n            new SimpleImmutableEntry<String, Expr>(\"add\", f000116),\n            new SimpleImmutableEntry<String, Expr>(\"clamp\", f000075),\n            new SimpleImmutableEntry<String, Expr>(\"equal\", f000135),\n            new SimpleImmutableEntry<String, Expr>(\"greaterThan\", f000152),\n            new SimpleImmutableEntry<String, Expr>(\"greaterThanEqual\", f000162),\n            new SimpleImmutableEntry<String, Expr>(\"lessThan\", f000165),\n            new SimpleImmutableEntry<String, Expr>(\"lessThanEqual\", f000167),\n            new SimpleImmutableEntry<String, Expr>(\"multiply\", f000184),\n            new SimpleImmutableEntry<String, Expr>(\"negate\", f000079),\n            new SimpleImmutableEntry<String, Expr>(\"negative\", f000187),\n            new SimpleImmutableEntry<String, Expr>(\"nonNegative\", f000188),\n            new SimpleImmutableEntry<String, Expr>(\"nonPositive\", f000189),\n            new SimpleImmutableEntry<String, Expr>(\"positive\", f000191),\n            new SimpleImmutableEntry<String, Expr>(\"show\", f000192),\n            new SimpleImmutableEntry<String, Expr>(\"subtract\", f000216),\n            new SimpleImmutableEntry<String, Expr>(\"toDouble\", f000217),\n            new SimpleImmutableEntry<String, Expr>(\"toNatural\", f000224)\n          });\n  private static final Expr f000226 = Expr.Constants.TEXT;\n  private static final Expr f000227 =\n      Expr.makeUnionType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Inline\", null),\n            new SimpleImmutableEntry<String, Expr>(\"Nested\", f000226)\n          });\n  private static final Expr f000228 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"contents\", f000070),\n            new SimpleImmutableEntry<String, Expr>(\"field\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"nesting\", f000227)\n          });\n  private static final Expr f000229 = Expr.makeLambda(\"a\", f000019, f000228);\n  private static final Expr f000230 = Expr.makeIdentifier(\"JSON\", 0);\n  private static final Expr f000231 = Expr.makeApplication(f000010, new Expr[] {f000230});\n  private static final Expr f000232 = Expr.makePi(\"_\", f000231, f000230);\n  private static final Expr f000233 = Expr.makePi(\"_\", f000001, f000230);\n  private static final Expr f000234 = Expr.Constants.DOUBLE;\n  private static final Expr f000235 = Expr.makePi(\"_\", f000234, f000230);\n  private static final Expr f000236 = Expr.makePi(\"_\", f000083, f000230);\n  private static final Expr f000237 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000230)\n          });\n  private static final Expr f000238 = Expr.makeApplication(f000010, new Expr[] {f000237});\n  private static final Expr f000239 = Expr.makePi(\"_\", f000238, f000230);\n  private static final Expr f000240 = Expr.makePi(\"_\", f000226, f000230);\n  private static final Expr f000241 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"array\", f000232),\n            new SimpleImmutableEntry<String, Expr>(\"bool\", f000233),\n            new SimpleImmutableEntry<String, Expr>(\"double\", f000235),\n            new SimpleImmutableEntry<String, Expr>(\"integer\", f000236),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000230),\n            new SimpleImmutableEntry<String, Expr>(\"object\", f000239),\n            new SimpleImmutableEntry<String, Expr>(\"string\", f000240)\n          });\n  private static final Expr f000242 = Expr.makePi(\"json\", f000241, f000230);\n  private static final Expr f000243 = Expr.makePi(\"JSON\", f000019, f000242);\n  private static final Expr f000244 = Expr.makeIdentifier(\"json\", 0);\n  private static final Expr f000245 = Expr.makeFieldAccess(f000244, \"array\");\n  private static final Expr f000246 = Expr.makeApplication(f000022, new Expr[] {f000230, f000244});\n  private static final Expr f000247 = Expr.makeNonEmptyListLiteral(new Expr[] {f000246});\n  private static final Expr f000248 = Expr.makeIdentifier(\"as\", 0);\n  private static final Expr f000249 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000247, f000248);\n  private static final Expr f000250 = Expr.makeLambda(\"as\", f000231, f000249);\n  private static final Expr f000251 = Expr.makeLambda(\"x\", f000243, f000250);\n  private static final Expr f000252 = Expr.makeEmptyListLiteral(f000231);\n  private static final Expr f000253 =\n      Expr.makeApplication(f000000, new Expr[] {f000243, f000022, f000231, f000251, f000252});\n  private static final Expr f000254 = Expr.makeApplication(f000245, new Expr[] {f000253});\n  private static final Expr f000255 = Expr.makeLambda(\"json\", f000241, f000254);\n  private static final Expr f000256 = Expr.makeLambda(\"JSON\", f000019, f000255);\n  private static final Expr f000257 = Expr.makeApplication(f000010, new Expr[] {f000243});\n  private static final Expr f000258 = Expr.makeLambda(\"x\", f000257, f000256);\n  private static final Expr f000259 = Expr.makeFieldAccess(f000244, \"bool\");\n  private static final Expr f000260 = Expr.makeApplication(f000259, new Expr[] {f000022});\n  private static final Expr f000261 = Expr.makeLambda(\"json\", f000241, f000260);\n  private static final Expr f000262 = Expr.makeLambda(\"JSON\", f000019, f000261);\n  private static final Expr f000263 = Expr.makeLambda(\"x\", f000001, f000262);\n  private static final Expr f000264 = Expr.makeFieldAccess(f000244, \"double\");\n  private static final Expr f000265 = Expr.makeApplication(f000264, new Expr[] {f000022});\n  private static final Expr f000266 = Expr.makeLambda(\"json\", f000241, f000265);\n  private static final Expr f000267 = Expr.makeLambda(\"JSON\", f000019, f000266);\n  private static final Expr f000268 = Expr.makeLambda(\"x\", f000234, f000267);\n  private static final Expr f000269 = Expr.makeFieldAccess(f000244, \"integer\");\n  private static final Expr f000270 = Expr.makeApplication(f000269, new Expr[] {f000022});\n  private static final Expr f000271 = Expr.makeLambda(\"json\", f000241, f000270);\n  private static final Expr f000272 = Expr.makeLambda(\"JSON\", f000019, f000271);\n  private static final Expr f000273 = Expr.makeLambda(\"x\", f000083, f000272);\n  private static final Expr f000274 = Expr.makeIdentifier(\"key\", 0);\n  private static final Expr f000275 = Expr.makeIdentifier(\"value\", 0);\n  private static final Expr f000276 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000274),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000275)\n          });\n  private static final Expr f000277 = Expr.makeLambda(\"value\", f000226, f000276);\n  private static final Expr f000278 = Expr.makeLambda(\"key\", f000226, f000277);\n  private static final Expr f000279 = Expr.makeIdentifier(\"v\", 0);\n  private static final Expr f000280 = Expr.makeLambda(\"value\", f000279, f000276);\n  private static final Expr f000281 = Expr.makeLambda(\"key\", f000226, f000280);\n  private static final Expr f000282 = Expr.makeLambda(\"v\", f000019, f000281);\n  private static final Expr f000283 = Expr.makeApplication(f000094, new Expr[] {f000022});\n  private static final Expr f000284 = Expr.makeApplication(f000269, new Expr[] {f000283});\n  private static final Expr f000285 = Expr.makeLambda(\"json\", f000241, f000284);\n  private static final Expr f000286 = Expr.makeLambda(\"JSON\", f000019, f000285);\n  private static final Expr f000287 = Expr.makeLambda(\"x\", f000221, f000286);\n  private static final Expr f000288 = Expr.makeFieldAccess(f000244, \"null\");\n  private static final Expr f000289 = Expr.makeLambda(\"json\", f000241, f000288);\n  private static final Expr f000290 = Expr.makeLambda(\"JSON\", f000019, f000289);\n  private static final Expr f000291 = Expr.makeFieldAccess(f000244, \"object\");\n  private static final Expr f000292 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000243)\n          });\n  private static final Expr f000293 = Expr.makeFieldAccess(f000022, \"mapKey\");\n  private static final Expr f000294 = Expr.makeFieldAccess(f000022, \"mapValue\");\n  private static final Expr f000295 = Expr.makeApplication(f000294, new Expr[] {f000230, f000244});\n  private static final Expr f000296 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000293),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000295)\n          });\n  private static final Expr f000297 = Expr.makeNonEmptyListLiteral(new Expr[] {f000296});\n  private static final Expr f000298 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000297, f000248);\n  private static final Expr f000299 = Expr.makeLambda(\"as\", f000238, f000298);\n  private static final Expr f000300 = Expr.makeLambda(\"x\", f000292, f000299);\n  private static final Expr f000301 = Expr.makeEmptyListLiteral(f000238);\n  private static final Expr f000302 =\n      Expr.makeApplication(f000000, new Expr[] {f000292, f000022, f000238, f000300, f000301});\n  private static final Expr f000303 = Expr.makeApplication(f000291, new Expr[] {f000302});\n  private static final Expr f000304 = Expr.makeLambda(\"json\", f000241, f000303);\n  private static final Expr f000305 = Expr.makeLambda(\"JSON\", f000019, f000304);\n  private static final Expr f000306 = Expr.makeApplication(f000010, new Expr[] {f000292});\n  private static final Expr f000307 = Expr.makeLambda(\"x\", f000306, f000305);\n  private static final Expr f000308 = Expr.makeIdentifier(\"old\", 0);\n  private static final Expr f000309 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000001),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000230)\n          });\n  private static final Expr f000310 = Expr.makeFieldAccess(f000022, \"value\");\n  private static final Expr f000311 = Expr.makeNonEmptyListLiteral(new Expr[] {f000310});\n  private static final Expr f000312 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000311, f000248);\n  private static final Expr f000313 = Expr.makeLambda(\"as\", f000231, f000312);\n  private static final Expr f000314 = Expr.makeLambda(\"x\", f000309, f000313);\n  private static final Expr f000315 =\n      Expr.makeApplication(f000000, new Expr[] {f000309, f000002, f000231, f000314, f000252});\n  private static final Expr f000316 = Expr.makeApplication(f000245, new Expr[] {f000315});\n  private static final Expr f000317 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000316)\n          });\n  private static final Expr f000318 = Expr.makeApplication(f000010, new Expr[] {f000309});\n  private static final Expr f000319 = Expr.makeLambda(\"xs\", f000318, f000317);\n  private static final Expr f000320 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000260)\n          });\n  private static final Expr f000321 = Expr.makeLambda(\"x\", f000001, f000320);\n  private static final Expr f000322 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000265)\n          });\n  private static final Expr f000323 = Expr.makeLambda(\"x\", f000234, f000322);\n  private static final Expr f000324 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000270)\n          });\n  private static final Expr f000325 = Expr.makeLambda(\"x\", f000083, f000324);\n  private static final Expr f000326 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000008),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000288)\n          });\n  private static final Expr f000327 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000309)\n          });\n  private static final Expr f000328 = Expr.makeIdentifier(\"keyValues\", 0);\n  private static final Expr f000329 = Expr.makeFieldAccess(f000294, \"isNull\");\n  private static final Expr f000330 = Expr.makeProjection(f000022, new String[] {\"mapKey\"});\n  private static final Expr f000331 = Expr.makeFieldAccess(f000294, \"value\");\n  private static final Expr f000332 =\n      Expr.makeRecordLiteral(\n          new Entry[] {new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000331)});\n  private static final Expr f000333 =\n      Expr.makeOperatorApplication(Operator.COMBINE, f000330, f000332);\n  private static final Expr f000334 = Expr.makeNonEmptyListLiteral(new Expr[] {f000333});\n  private static final Expr f000335 = Expr.makeIf(f000329, f000301, f000334);\n  private static final Expr f000336 = Expr.makeNonEmptyListLiteral(new Expr[] {f000070});\n  private static final Expr f000337 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000336, f000248);\n  private static final Expr f000338 = Expr.makeLambda(\"as\", f000238, f000337);\n  private static final Expr f000339 = Expr.makeLambda(\"a\", f000237, f000338);\n  private static final Expr f000340 =\n      Expr.makeApplication(f000000, new Expr[] {f000237, f000335, f000238, f000339});\n  private static final Expr f000341 = Expr.makeLambda(\"x\", f000327, f000340);\n  private static final Expr f000342 =\n      Expr.makeApplication(f000000, new Expr[] {f000327, f000328, f000238, f000341, f000301});\n  private static final Expr f000343 = Expr.makeApplication(f000291, new Expr[] {f000342});\n  private static final Expr f000344 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000343)\n          });\n  private static final Expr f000345 = Expr.makeApplication(f000010, new Expr[] {f000327});\n  private static final Expr f000346 = Expr.makeLambda(\"keyValues\", f000345, f000344);\n  private static final Expr f000347 = Expr.makeFieldAccess(f000244, \"string\");\n  private static final Expr f000348 = Expr.makeApplication(f000347, new Expr[] {f000022});\n  private static final Expr f000349 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"isNull\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000348)\n          });\n  private static final Expr f000350 = Expr.makeLambda(\"x\", f000226, f000349);\n  private static final Expr f000351 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"array\", f000319),\n            new SimpleImmutableEntry<String, Expr>(\"bool\", f000321),\n            new SimpleImmutableEntry<String, Expr>(\"double\", f000323),\n            new SimpleImmutableEntry<String, Expr>(\"integer\", f000325),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000326),\n            new SimpleImmutableEntry<String, Expr>(\"object\", f000346),\n            new SimpleImmutableEntry<String, Expr>(\"string\", f000350)\n          });\n  private static final Expr f000352 = Expr.makeApplication(f000308, new Expr[] {f000309, f000351});\n  private static final Expr f000353 = Expr.makeFieldAccess(f000352, \"value\");\n  private static final Expr f000354 = Expr.makeLambda(\"json\", f000241, f000353);\n  private static final Expr f000355 = Expr.makeLambda(\"JSON\", f000019, f000354);\n  private static final Expr f000356 = Expr.makeLambda(\"old\", f000243, f000355);\n  private static final Expr f000357 = Expr.makeApplication(f000010, new Expr[] {f000226});\n  private static final Expr f000358 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000357)\n          });\n  private static final Expr f000359 = Expr.makeLambda(\"x\", f000358, f000022);\n  private static final Expr f000360 = Expr.makeEmptyListLiteral(f000357);\n  private static final Expr f000361 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000022),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000362 = Expr.makeLambda(\"x\", f000226, f000361);\n  private static final Expr f000363 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Complex\", f000359),\n            new SimpleImmutableEntry<String, Expr>(\"Simple\", f000362)\n          });\n  private static final Expr f000364 =\n      Expr.makeUnionType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Complex\", f000358),\n            new SimpleImmutableEntry<String, Expr>(\"Simple\", f000226)\n          });\n  private static final Expr f000365 = Expr.makeFieldAccess(f000364, \"Simple\");\n  private static final Expr f000366 = Expr.makeTextLiteral(\"[]\");\n  private static final Expr f000367 = Expr.makeApplication(f000365, new Expr[] {f000366});\n  private static final Expr f000368 = Expr.makeFieldAccess(f000364, \"Complex\");\n  private static final Expr f000369 = Expr.makeIdentifier(\"inputs\", 0);\n  private static final Expr f000370 = Expr.makeFieldAccess(f000369, \"head\");\n  private static final Expr f000371 = Expr.makeMerge(f000363, f000370, null);\n  private static final Expr f000372 = Expr.makeFieldAccess(f000369, \"tail\");\n  private static final Expr f000373 = Expr.makeApplication(f000010, new Expr[] {f000358});\n  private static final Expr f000374 = Expr.makeMerge(f000363, f000022, null);\n  private static final Expr f000375 = Expr.makeNonEmptyListLiteral(new Expr[] {f000374});\n  private static final Expr f000376 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000375, f000248);\n  private static final Expr f000377 = Expr.makeLambda(\"as\", f000373, f000376);\n  private static final Expr f000378 = Expr.makeLambda(\"x\", f000364, f000377);\n  private static final Expr f000379 = Expr.makeEmptyListLiteral(f000373);\n  private static final Expr f000380 =\n      Expr.makeApplication(f000000, new Expr[] {f000364, f000372, f000373, f000378, f000379});\n  private static final Expr f000381 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000371),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000380)\n          });\n  private static final Expr f000382 = Expr.makeFieldAccess(f000371, \"head\");\n  private static final Expr f000383 =\n      Expr.makeTextLiteral(new String[] {\"\", \",\"}, new Expr[] {f000382});\n  private static final Expr f000384 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000383),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000385 = Expr.makeFieldAccess(f000022, \"init\");\n  private static final Expr f000386 = Expr.makeFieldAccess(f000022, \"last\");\n  private static final Expr f000387 =\n      Expr.makeTextLiteral(new String[] {\"\", \",\"}, new Expr[] {f000386});\n  private static final Expr f000388 = Expr.makeNonEmptyListLiteral(new Expr[] {f000387});\n  private static final Expr f000389 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000385, f000388);\n  private static final Expr f000390 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"tail\", f000389)});\n  private static final Expr f000391 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000371, f000390);\n  private static final Expr f000392 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"init\", f000357),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f000226)\n          });\n  private static final Expr f000393 = Expr.makeLambda(\"x\", f000392, f000391);\n  private static final Expr f000394 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000384),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000393)\n          });\n  private static final Expr f000395 = Expr.makeFieldAccess(f000371, \"tail\");\n  private static final Expr f000396 = Expr.makeBuiltIn(\"Optional\");\n  private static final Expr f000397 = Expr.makeApplication(f000396, new Expr[] {f000392});\n  private static final Expr f000398 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"init\", f000360),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f000022)\n          });\n  private static final Expr f000399 = Expr.makeApplication(f000218, new Expr[] {f000398});\n  private static final Expr f000400 = Expr.makeIdentifier(\"ny\", 0);\n  private static final Expr f000401 = Expr.makeNonEmptyListLiteral(new Expr[] {f000022});\n  private static final Expr f000402 = Expr.makeFieldAccess(f000400, \"init\");\n  private static final Expr f000403 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000401, f000402);\n  private static final Expr f000404 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"init\", f000403)});\n  private static final Expr f000405 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000400, f000404);\n  private static final Expr f000406 = Expr.makeApplication(f000218, new Expr[] {f000405});\n  private static final Expr f000407 = Expr.makeLambda(\"ny\", f000392, f000406);\n  private static final Expr f000408 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000399),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000407)\n          });\n  private static final Expr f000409 = Expr.makeIdentifier(\"acc\", 0);\n  private static final Expr f000410 = Expr.makeMerge(f000408, f000409, null);\n  private static final Expr f000411 = Expr.makeLambda(\"acc\", f000397, f000410);\n  private static final Expr f000412 = Expr.makeLambda(\"x\", f000226, f000411);\n  private static final Expr f000413 = Expr.makeApplication(f000220, new Expr[] {f000392});\n  private static final Expr f000414 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000395, f000397, f000412, f000413});\n  private static final Expr f000415 = Expr.makeMerge(f000394, f000414, null);\n  private static final Expr f000416 = Expr.makeFieldAccess(f000022, \"head\");\n  private static final Expr f000417 =\n      Expr.makeTextLiteral(new String[] {\"\", \",\"}, new Expr[] {f000416});\n  private static final Expr f000418 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000417),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000419 = Expr.makeIdentifier(\"x\", 1);\n  private static final Expr f000420 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000419, f000390);\n  private static final Expr f000421 = Expr.makeLambda(\"x\", f000392, f000420);\n  private static final Expr f000422 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000418),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000421)\n          });\n  private static final Expr f000423 = Expr.makeFieldAccess(f000022, \"tail\");\n  private static final Expr f000424 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000423, f000397, f000412, f000413});\n  private static final Expr f000425 = Expr.makeMerge(f000422, f000424, null);\n  private static final Expr f000426 = Expr.makeNonEmptyListLiteral(new Expr[] {f000425});\n  private static final Expr f000427 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000426, f000248);\n  private static final Expr f000428 = Expr.makeLambda(\"as\", f000373, f000427);\n  private static final Expr f000429 = Expr.makeLambda(\"x\", f000358, f000428);\n  private static final Expr f000430 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000385, f000373, f000429, f000379});\n  private static final Expr f000431 = Expr.makeNonEmptyListLiteral(new Expr[] {f000386});\n  private static final Expr f000432 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000430, f000431);\n  private static final Expr f000433 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000415),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000432)\n          });\n  private static final Expr f000434 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"init\", f000373),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f000358)\n          });\n  private static final Expr f000435 = Expr.makeLambda(\"x\", f000434, f000433);\n  private static final Expr f000436 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000381),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000435)\n          });\n  private static final Expr f000437 = Expr.makeApplication(f000396, new Expr[] {f000434});\n  private static final Expr f000438 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"init\", f000379),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f000022)\n          });\n  private static final Expr f000439 = Expr.makeApplication(f000218, new Expr[] {f000438});\n  private static final Expr f000440 = Expr.makeLambda(\"ny\", f000434, f000406);\n  private static final Expr f000441 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000439),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000440)\n          });\n  private static final Expr f000442 = Expr.makeMerge(f000441, f000409, null);\n  private static final Expr f000443 = Expr.makeLambda(\"acc\", f000437, f000442);\n  private static final Expr f000444 = Expr.makeLambda(\"x\", f000358, f000443);\n  private static final Expr f000445 = Expr.makeApplication(f000220, new Expr[] {f000434});\n  private static final Expr f000446 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000380, f000437, f000444, f000445});\n  private static final Expr f000447 = Expr.makeMerge(f000436, f000446, null);\n  private static final Expr f000448 = Expr.makeFieldAccess(f000447, \"head\");\n  private static final Expr f000449 = Expr.makeFieldAccess(f000448, \"head\");\n  private static final Expr f000450 =\n      Expr.makeTextLiteral(new String[] {\"[ \", \" ]\"}, new Expr[] {f000449});\n  private static final Expr f000451 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000450),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000452 = Expr.makeTextLiteral(\"[\");\n  private static final Expr f000453 = Expr.makeNonEmptyListLiteral(new Expr[] {f000449});\n  private static final Expr f000454 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000453, f000402);\n  private static final Expr f000455 = Expr.makeFieldAccess(f000400, \"last\");\n  private static final Expr f000456 = Expr.makeNonEmptyListLiteral(new Expr[] {f000455});\n  private static final Expr f000457 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000454, f000456);\n  private static final Expr f000458 =\n      Expr.makeTextLiteral(new String[] {\"  \", \"\"}, new Expr[] {f000022});\n  private static final Expr f000459 = Expr.makeNonEmptyListLiteral(new Expr[] {f000458});\n  private static final Expr f000460 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000459, f000248);\n  private static final Expr f000461 = Expr.makeLambda(\"as\", f000357, f000460);\n  private static final Expr f000462 = Expr.makeLambda(\"x\", f000226, f000461);\n  private static final Expr f000463 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000457, f000357, f000462, f000360});\n  private static final Expr f000464 = Expr.makeTextLiteral(\"]\");\n  private static final Expr f000465 = Expr.makeNonEmptyListLiteral(new Expr[] {f000464});\n  private static final Expr f000466 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000463, f000465);\n  private static final Expr f000467 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000452),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000466)\n          });\n  private static final Expr f000468 = Expr.makeLambda(\"ny\", f000392, f000467);\n  private static final Expr f000469 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000451),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000468)\n          });\n  private static final Expr f000470 = Expr.makeFieldAccess(f000448, \"tail\");\n  private static final Expr f000471 = Expr.makeFieldAccess(f000447, \"tail\");\n  private static final Expr f000472 = Expr.makeNonEmptyListLiteral(new Expr[] {f000416});\n  private static final Expr f000473 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000472, f000423);\n  private static final Expr f000474 = Expr.makeLambda(\"as\", f000357, f000337);\n  private static final Expr f000475 = Expr.makeLambda(\"a\", f000226, f000474);\n  private static final Expr f000476 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000473, f000357, f000475});\n  private static final Expr f000477 = Expr.makeLambda(\"x\", f000358, f000476);\n  private static final Expr f000478 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000471, f000357, f000477, f000360});\n  private static final Expr f000479 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000470, f000478);\n  private static final Expr f000480 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000479, f000397, f000412, f000413});\n  private static final Expr f000481 = Expr.makeMerge(f000469, f000480, null);\n  private static final Expr f000482 = Expr.makeApplication(f000368, new Expr[] {f000481});\n  private static final Expr f000483 = Expr.makeApplication(f000010, new Expr[] {f000364});\n  private static final Expr f000484 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000364),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000483)\n          });\n  private static final Expr f000485 = Expr.makeLambda(\"inputs\", f000484, f000482);\n  private static final Expr f000486 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000367),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000485)\n          });\n  private static final Expr f000487 = Expr.makeBuiltIn(\"List/reverse\");\n  private static final Expr f000488 = Expr.makeApplication(f000487, new Expr[] {f000364, f000369});\n  private static final Expr f000489 = Expr.makeApplication(f000396, new Expr[] {f000484});\n  private static final Expr f000490 = Expr.makeEmptyListLiteral(f000483);\n  private static final Expr f000491 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000022),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000490)\n          });\n  private static final Expr f000492 = Expr.makeApplication(f000218, new Expr[] {f000491});\n  private static final Expr f000493 = Expr.makeIdentifier(\"ne\", 0);\n  private static final Expr f000494 = Expr.makeFieldAccess(f000493, \"tail\");\n  private static final Expr f000495 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000494, f000401);\n  private static final Expr f000496 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"tail\", f000495)});\n  private static final Expr f000497 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000493, f000496);\n  private static final Expr f000498 = Expr.makeApplication(f000218, new Expr[] {f000497});\n  private static final Expr f000499 = Expr.makeLambda(\"ne\", f000484, f000498);\n  private static final Expr f000500 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000492),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000499)\n          });\n  private static final Expr f000501 = Expr.makeMerge(f000500, f000409, null);\n  private static final Expr f000502 = Expr.makeLambda(\"acc\", f000489, f000501);\n  private static final Expr f000503 = Expr.makeLambda(\"x\", f000364, f000502);\n  private static final Expr f000504 = Expr.makeApplication(f000220, new Expr[] {f000484});\n  private static final Expr f000505 =\n      Expr.makeApplication(f000000, new Expr[] {f000364, f000488, f000489, f000503, f000504});\n  private static final Expr f000506 = Expr.makeMerge(f000486, f000505, null);\n  private static final Expr f000507 = Expr.makeLambda(\"inputs\", f000483, f000506);\n  private static final Expr f000508 = Expr.makeTextLiteral(\"true\");\n  private static final Expr f000509 = Expr.makeTextLiteral(\"false\");\n  private static final Expr f000510 = Expr.makeIf(f000022, f000508, f000509);\n  private static final Expr f000511 = Expr.makeApplication(f000365, new Expr[] {f000510});\n  private static final Expr f000512 = Expr.makeLambda(\"x\", f000001, f000511);\n  private static final Expr f000513 = Expr.makeApplication(f000054, new Expr[] {f000022});\n  private static final Expr f000514 = Expr.makeApplication(f000365, new Expr[] {f000513});\n  private static final Expr f000515 = Expr.makeLambda(\"x\", f000234, f000514);\n  private static final Expr f000516 = Expr.makeBuiltIn(\"Natural/show\");\n  private static final Expr f000517 = Expr.makeApplication(f000516, new Expr[] {f000136});\n  private static final Expr f000518 = Expr.makeApplication(f000192, new Expr[] {f000022});\n  private static final Expr f000519 = Expr.makeIf(f000154, f000517, f000518);\n  private static final Expr f000520 = Expr.makeApplication(f000365, new Expr[] {f000519});\n  private static final Expr f000521 = Expr.makeLambda(\"x\", f000083, f000520);\n  private static final Expr f000522 = Expr.makeTextLiteral(\"null\");\n  private static final Expr f000523 = Expr.makeApplication(f000365, new Expr[] {f000522});\n  private static final Expr f000524 = Expr.makeTextLiteral(\"{}\");\n  private static final Expr f000525 = Expr.makeApplication(f000365, new Expr[] {f000524});\n  private static final Expr f000526 = Expr.makeFieldAccess(f000370, \"mapValue\");\n  private static final Expr f000527 = Expr.makeMerge(f000363, f000526, null);\n  private static final Expr f000528 = Expr.makeBuiltIn(\"Text/replace\");\n  private static final Expr f000529 = Expr.makeTextLiteral(\"\\\"\");\n  private static final Expr f000530 = Expr.makeTextLiteral(\"\\\\\\\\\\\"\");\n  private static final Expr f000531 = Expr.makeTextLiteral(\"\\b\");\n  private static final Expr f000532 = Expr.makeTextLiteral(\"\\\\\\\\b\");\n  private static final Expr f000533 = Expr.makeTextLiteral(\"\\f\");\n  private static final Expr f000534 = Expr.makeTextLiteral(\"\\\\\\\\f\");\n  private static final Expr f000535 = Expr.makeTextLiteral(\"\\n\");\n  private static final Expr f000536 = Expr.makeTextLiteral(\"\\\\\\\\n\");\n  private static final Expr f000537 = Expr.makeTextLiteral(\"\\r\");\n  private static final Expr f000538 = Expr.makeTextLiteral(\"\\\\\\\\r\");\n  private static final Expr f000539 = Expr.makeTextLiteral(\"\\t\");\n  private static final Expr f000540 = Expr.makeTextLiteral(\"\\\\\\\\t\");\n  private static final Expr f000541 = Expr.makeTextLiteral(\"\\\\\\\\\");\n  private static final Expr f000542 = Expr.makeTextLiteral(\"\\\\\\\\\\\\\\\\\");\n  private static final Expr f000543 = Expr.makeFieldAccess(f000370, \"mapKey\");\n  private static final Expr f000544 =\n      Expr.makeApplication(f000528, new Expr[] {f000541, f000542, f000543});\n  private static final Expr f000545 =\n      Expr.makeApplication(f000528, new Expr[] {f000539, f000540, f000544});\n  private static final Expr f000546 =\n      Expr.makeApplication(f000528, new Expr[] {f000537, f000538, f000545});\n  private static final Expr f000547 =\n      Expr.makeApplication(f000528, new Expr[] {f000535, f000536, f000546});\n  private static final Expr f000548 =\n      Expr.makeApplication(f000528, new Expr[] {f000533, f000534, f000547});\n  private static final Expr f000549 =\n      Expr.makeApplication(f000528, new Expr[] {f000531, f000532, f000548});\n  private static final Expr f000550 =\n      Expr.makeApplication(f000528, new Expr[] {f000529, f000530, f000549});\n  private static final Expr f000551 = Expr.makeFieldAccess(f000527, \"head\");\n  private static final Expr f000552 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\": \", \"\"}, new Expr[] {f000550, f000551});\n  private static final Expr f000553 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"head\", f000552)});\n  private static final Expr f000554 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000527, f000553);\n  private static final Expr f000555 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000364)\n          });\n  private static final Expr f000556 = Expr.makeMerge(f000363, f000294, null);\n  private static final Expr f000557 =\n      Expr.makeApplication(f000528, new Expr[] {f000541, f000542, f000293});\n  private static final Expr f000558 =\n      Expr.makeApplication(f000528, new Expr[] {f000539, f000540, f000557});\n  private static final Expr f000559 =\n      Expr.makeApplication(f000528, new Expr[] {f000537, f000538, f000558});\n  private static final Expr f000560 =\n      Expr.makeApplication(f000528, new Expr[] {f000535, f000536, f000559});\n  private static final Expr f000561 =\n      Expr.makeApplication(f000528, new Expr[] {f000533, f000534, f000560});\n  private static final Expr f000562 =\n      Expr.makeApplication(f000528, new Expr[] {f000531, f000532, f000561});\n  private static final Expr f000563 =\n      Expr.makeApplication(f000528, new Expr[] {f000529, f000530, f000562});\n  private static final Expr f000564 = Expr.makeFieldAccess(f000556, \"head\");\n  private static final Expr f000565 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\": \", \"\"}, new Expr[] {f000563, f000564});\n  private static final Expr f000566 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"head\", f000565)});\n  private static final Expr f000567 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000556, f000566);\n  private static final Expr f000568 = Expr.makeNonEmptyListLiteral(new Expr[] {f000567});\n  private static final Expr f000569 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000568, f000248);\n  private static final Expr f000570 = Expr.makeLambda(\"as\", f000373, f000569);\n  private static final Expr f000571 = Expr.makeLambda(\"x\", f000555, f000570);\n  private static final Expr f000572 =\n      Expr.makeApplication(f000000, new Expr[] {f000555, f000372, f000373, f000571, f000379});\n  private static final Expr f000573 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000554),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000572)\n          });\n  private static final Expr f000574 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\": \", \",\"}, new Expr[] {f000550, f000551});\n  private static final Expr f000575 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000574),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000576 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000554, f000390);\n  private static final Expr f000577 = Expr.makeLambda(\"x\", f000392, f000576);\n  private static final Expr f000578 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000575),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000577)\n          });\n  private static final Expr f000579 = Expr.makeFieldAccess(f000527, \"tail\");\n  private static final Expr f000580 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000579, f000397, f000412, f000413});\n  private static final Expr f000581 = Expr.makeMerge(f000578, f000580, null);\n  private static final Expr f000582 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000581),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000432)\n          });\n  private static final Expr f000583 = Expr.makeLambda(\"x\", f000434, f000582);\n  private static final Expr f000584 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000573),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000583)\n          });\n  private static final Expr f000585 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000572, f000437, f000444, f000445});\n  private static final Expr f000586 = Expr.makeMerge(f000584, f000585, null);\n  private static final Expr f000587 = Expr.makeFieldAccess(f000586, \"head\");\n  private static final Expr f000588 = Expr.makeFieldAccess(f000587, \"head\");\n  private static final Expr f000589 =\n      Expr.makeTextLiteral(new String[] {\"{ \", \" }\"}, new Expr[] {f000588});\n  private static final Expr f000590 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000589),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000591 = Expr.makeTextLiteral(\"{\");\n  private static final Expr f000592 = Expr.makeNonEmptyListLiteral(new Expr[] {f000588});\n  private static final Expr f000593 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000592, f000402);\n  private static final Expr f000594 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000593, f000456);\n  private static final Expr f000595 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000594, f000357, f000462, f000360});\n  private static final Expr f000596 = Expr.makeTextLiteral(\"}\");\n  private static final Expr f000597 = Expr.makeNonEmptyListLiteral(new Expr[] {f000596});\n  private static final Expr f000598 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000595, f000597);\n  private static final Expr f000599 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000591),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000598)\n          });\n  private static final Expr f000600 = Expr.makeLambda(\"ny\", f000392, f000599);\n  private static final Expr f000601 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000590),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000600)\n          });\n  private static final Expr f000602 = Expr.makeFieldAccess(f000587, \"tail\");\n  private static final Expr f000603 = Expr.makeFieldAccess(f000586, \"tail\");\n  private static final Expr f000604 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000603, f000357, f000477, f000360});\n  private static final Expr f000605 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000602, f000604);\n  private static final Expr f000606 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000605, f000397, f000412, f000413});\n  private static final Expr f000607 = Expr.makeMerge(f000601, f000606, null);\n  private static final Expr f000608 = Expr.makeApplication(f000368, new Expr[] {f000607});\n  private static final Expr f000609 = Expr.makeApplication(f000010, new Expr[] {f000555});\n  private static final Expr f000610 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000555),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000609)\n          });\n  private static final Expr f000611 = Expr.makeLambda(\"inputs\", f000610, f000608);\n  private static final Expr f000612 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000525),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000611)\n          });\n  private static final Expr f000613 = Expr.makeApplication(f000487, new Expr[] {f000555, f000369});\n  private static final Expr f000614 = Expr.makeApplication(f000396, new Expr[] {f000610});\n  private static final Expr f000615 = Expr.makeEmptyListLiteral(f000609);\n  private static final Expr f000616 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000022),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000615)\n          });\n  private static final Expr f000617 = Expr.makeApplication(f000218, new Expr[] {f000616});\n  private static final Expr f000618 = Expr.makeLambda(\"ne\", f000610, f000498);\n  private static final Expr f000619 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000617),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000618)\n          });\n  private static final Expr f000620 = Expr.makeMerge(f000619, f000409, null);\n  private static final Expr f000621 = Expr.makeLambda(\"acc\", f000614, f000620);\n  private static final Expr f000622 = Expr.makeLambda(\"x\", f000555, f000621);\n  private static final Expr f000623 = Expr.makeApplication(f000220, new Expr[] {f000610});\n  private static final Expr f000624 =\n      Expr.makeApplication(f000000, new Expr[] {f000555, f000613, f000614, f000622, f000623});\n  private static final Expr f000625 = Expr.makeMerge(f000612, f000624, null);\n  private static final Expr f000626 = Expr.makeLambda(\"inputs\", f000609, f000625);\n  private static final Expr f000627 =\n      Expr.makeApplication(f000528, new Expr[] {f000541, f000542, f000022});\n  private static final Expr f000628 =\n      Expr.makeApplication(f000528, new Expr[] {f000539, f000540, f000627});\n  private static final Expr f000629 =\n      Expr.makeApplication(f000528, new Expr[] {f000537, f000538, f000628});\n  private static final Expr f000630 =\n      Expr.makeApplication(f000528, new Expr[] {f000535, f000536, f000629});\n  private static final Expr f000631 =\n      Expr.makeApplication(f000528, new Expr[] {f000533, f000534, f000630});\n  private static final Expr f000632 =\n      Expr.makeApplication(f000528, new Expr[] {f000531, f000532, f000631});\n  private static final Expr f000633 =\n      Expr.makeApplication(f000528, new Expr[] {f000529, f000530, f000632});\n  private static final Expr f000634 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\"\"}, new Expr[] {f000633});\n  private static final Expr f000635 = Expr.makeApplication(f000365, new Expr[] {f000634});\n  private static final Expr f000636 = Expr.makeLambda(\"x\", f000226, f000635);\n  private static final Expr f000637 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"array\", f000507),\n            new SimpleImmutableEntry<String, Expr>(\"bool\", f000512),\n            new SimpleImmutableEntry<String, Expr>(\"double\", f000515),\n            new SimpleImmutableEntry<String, Expr>(\"integer\", f000521),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000523),\n            new SimpleImmutableEntry<String, Expr>(\"object\", f000626),\n            new SimpleImmutableEntry<String, Expr>(\"string\", f000636)\n          });\n  private static final Expr f000638 = Expr.makeApplication(f000244, new Expr[] {f000364, f000637});\n  private static final Expr f000639 = Expr.makeMerge(f000363, f000638, null);\n  private static final Expr f000640 = Expr.makeFieldAccess(f000639, \"head\");\n  private static final Expr f000641 = Expr.makeNonEmptyListLiteral(new Expr[] {f000640});\n  private static final Expr f000642 = Expr.makeFieldAccess(f000639, \"tail\");\n  private static final Expr f000643 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000641, f000642);\n  private static final Expr f000644 =\n      Expr.makeTextLiteral(new String[] {\"\", \"\\n\", \"\"}, new Expr[] {f000022, f000023});\n  private static final Expr f000645 = Expr.makeLambda(\"y\", f000226, f000644);\n  private static final Expr f000646 = Expr.makeLambda(\"x\", f000226, f000645);\n  private static final Expr f000647 = Expr.makeTextLiteral(\"\");\n  private static final Expr f000648 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000643, f000226, f000646, f000647});\n  private static final Expr f000649 = Expr.makeLambda(\"json\", f000243, f000648);\n  private static final Expr f000650 = Expr.makeIdentifier(\"j\", 0);\n  private static final Expr f000651 = Expr.makeIdentifier(\"result\", 0);\n  private static final Expr f000652 = Expr.makeLambda(\"result\", f000226, f000651);\n  private static final Expr f000653 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Empty\", f000647),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f000652)\n          });\n  private static final Expr f000654 =\n      Expr.makeUnionType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Empty\", null),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f000226)\n          });\n  private static final Expr f000655 = Expr.makeFieldAccess(f000654, \"NonEmpty\");\n  private static final Expr f000656 =\n      Expr.makeTextLiteral(new String[] {\" \", \"\"}, new Expr[] {f000022});\n  private static final Expr f000657 = Expr.makeApplication(f000655, new Expr[] {f000656});\n  private static final Expr f000658 =\n      Expr.makeTextLiteral(new String[] {\" \", \",\", \"\"}, new Expr[] {f000022, f000651});\n  private static final Expr f000659 = Expr.makeApplication(f000655, new Expr[] {f000658});\n  private static final Expr f000660 = Expr.makeLambda(\"result\", f000226, f000659);\n  private static final Expr f000661 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Empty\", f000657),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f000660)\n          });\n  private static final Expr f000662 = Expr.makeIdentifier(\"status\", 0);\n  private static final Expr f000663 = Expr.makeMerge(f000661, f000662, null);\n  private static final Expr f000664 = Expr.makeLambda(\"status\", f000654, f000663);\n  private static final Expr f000665 = Expr.makeLambda(\"x\", f000226, f000664);\n  private static final Expr f000666 = Expr.makeFieldAccess(f000654, \"Empty\");\n  private static final Expr f000667 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000022, f000654, f000665, f000666});\n  private static final Expr f000668 = Expr.makeMerge(f000653, f000667, null);\n  private static final Expr f000669 =\n      Expr.makeTextLiteral(new String[] {\"[\", \" ]\"}, new Expr[] {f000668});\n  private static final Expr f000670 = Expr.makeLambda(\"x\", f000357, f000669);\n  private static final Expr f000671 = Expr.makeLambda(\"x\", f000001, f000510);\n  private static final Expr f000672 = Expr.makeIdentifier(\"integer\", 0);\n  private static final Expr f000673 = Expr.makeApplication(f000079, new Expr[] {f000672});\n  private static final Expr f000674 = Expr.makeApplication(f000075, new Expr[] {f000673});\n  private static final Expr f000675 = Expr.makeApplication(f000074, new Expr[] {f000674});\n  private static final Expr f000676 = Expr.makeApplication(f000075, new Expr[] {f000672});\n  private static final Expr f000677 = Expr.makeApplication(f000516, new Expr[] {f000676});\n  private static final Expr f000678 = Expr.makeApplication(f000192, new Expr[] {f000672});\n  private static final Expr f000679 = Expr.makeIf(f000675, f000677, f000678);\n  private static final Expr f000680 = Expr.makeLambda(\"integer\", f000083, f000679);\n  private static final Expr f000681 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000226)\n          });\n  private static final Expr f000682 = Expr.makeBuiltIn(\"Text/show\");\n  private static final Expr f000683 = Expr.makeApplication(f000682, new Expr[] {f000293});\n  private static final Expr f000684 =\n      Expr.makeTextLiteral(new String[] {\" \", \": \", \"\"}, new Expr[] {f000683, f000294});\n  private static final Expr f000685 = Expr.makeApplication(f000655, new Expr[] {f000684});\n  private static final Expr f000686 =\n      Expr.makeTextLiteral(\n          new String[] {\" \", \": \", \",\", \"\"}, new Expr[] {f000683, f000294, f000651});\n  private static final Expr f000687 = Expr.makeApplication(f000655, new Expr[] {f000686});\n  private static final Expr f000688 = Expr.makeLambda(\"result\", f000226, f000687);\n  private static final Expr f000689 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Empty\", f000685),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f000688)\n          });\n  private static final Expr f000690 = Expr.makeMerge(f000689, f000662, null);\n  private static final Expr f000691 = Expr.makeLambda(\"status\", f000654, f000690);\n  private static final Expr f000692 = Expr.makeLambda(\"x\", f000681, f000691);\n  private static final Expr f000693 =\n      Expr.makeApplication(f000000, new Expr[] {f000681, f000022, f000654, f000692, f000666});\n  private static final Expr f000694 = Expr.makeMerge(f000653, f000693, null);\n  private static final Expr f000695 =\n      Expr.makeTextLiteral(new String[] {\"{\", \" }\"}, new Expr[] {f000694});\n  private static final Expr f000696 = Expr.makeApplication(f000010, new Expr[] {f000681});\n  private static final Expr f000697 = Expr.makeLambda(\"x\", f000696, f000695);\n  private static final Expr f000698 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"array\", f000670),\n            new SimpleImmutableEntry<String, Expr>(\"bool\", f000671),\n            new SimpleImmutableEntry<String, Expr>(\"double\", f000054),\n            new SimpleImmutableEntry<String, Expr>(\"integer\", f000680),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000522),\n            new SimpleImmutableEntry<String, Expr>(\"object\", f000697),\n            new SimpleImmutableEntry<String, Expr>(\"string\", f000682)\n          });\n  private static final Expr f000699 = Expr.makeApplication(f000650, new Expr[] {f000226, f000698});\n  private static final Expr f000700 = Expr.makeLambda(\"j\", f000243, f000699);\n  private static final Expr f000701 =\n      Expr.makeTextLiteral(new String[] {\"- \", \"\"}, new Expr[] {f000382});\n  private static final Expr f000702 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000395, f000357, f000462, f000360});\n  private static final Expr f000703 = Expr.makeFieldAccess(f000374, \"tail\");\n  private static final Expr f000704 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000703, f000357, f000462, f000360});\n  private static final Expr f000705 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"tail\", f000704)});\n  private static final Expr f000706 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000374, f000705);\n  private static final Expr f000707 = Expr.makeFieldAccess(f000374, \"head\");\n  private static final Expr f000708 =\n      Expr.makeTextLiteral(new String[] {\"- \", \"\"}, new Expr[] {f000707});\n  private static final Expr f000709 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"head\", f000708)});\n  private static final Expr f000710 =\n      Expr.makeOperatorApplication(Operator.PREFER, f000706, f000709);\n  private static final Expr f000711 = Expr.makeNonEmptyListLiteral(new Expr[] {f000710});\n  private static final Expr f000712 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000711, f000248);\n  private static final Expr f000713 = Expr.makeLambda(\"as\", f000373, f000712);\n  private static final Expr f000714 = Expr.makeLambda(\"x\", f000364, f000713);\n  private static final Expr f000715 =\n      Expr.makeApplication(f000000, new Expr[] {f000364, f000372, f000373, f000714, f000379});\n  private static final Expr f000716 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000715, f000357, f000477, f000360});\n  private static final Expr f000717 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000702, f000716);\n  private static final Expr f000718 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000701),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000717)\n          });\n  private static final Expr f000719 = Expr.makeApplication(f000368, new Expr[] {f000718});\n  private static final Expr f000720 = Expr.makeLambda(\"inputs\", f000484, f000719);\n  private static final Expr f000721 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000367),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000720)\n          });\n  private static final Expr f000722 = Expr.makeMerge(f000721, f000505, null);\n  private static final Expr f000723 = Expr.makeLambda(\"inputs\", f000483, f000722);\n  private static final Expr f000724 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\":\"}, new Expr[] {f000550});\n  private static final Expr f000725 = Expr.makeNonEmptyListLiteral(new Expr[] {f000551});\n  private static final Expr f000726 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000725, f000579);\n  private static final Expr f000727 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000726, f000357, f000462, f000360});\n  private static final Expr f000728 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000724),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000727)\n          });\n  private static final Expr f000729 = Expr.makeLambda(\"_\", f000358, f000728);\n  private static final Expr f000730 = Expr.makeIdentifier(\"line\", 0);\n  private static final Expr f000731 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\": \", \"\"}, new Expr[] {f000550, f000730});\n  private static final Expr f000732 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000731),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000733 = Expr.makeLambda(\"line\", f000226, f000732);\n  private static final Expr f000734 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Complex\", f000729),\n            new SimpleImmutableEntry<String, Expr>(\"Simple\", f000733)\n          });\n  private static final Expr f000735 = Expr.makeMerge(f000734, f000526, null);\n  private static final Expr f000736 = Expr.makeFieldAccess(f000735, \"head\");\n  private static final Expr f000737 = Expr.makeFieldAccess(f000735, \"tail\");\n  private static final Expr f000738 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\":\"}, new Expr[] {f000563});\n  private static final Expr f000739 = Expr.makeNonEmptyListLiteral(new Expr[] {f000564});\n  private static final Expr f000740 = Expr.makeFieldAccess(f000556, \"tail\");\n  private static final Expr f000741 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000739, f000740);\n  private static final Expr f000742 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000741, f000357, f000462, f000360});\n  private static final Expr f000743 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000738),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000742)\n          });\n  private static final Expr f000744 = Expr.makeLambda(\"_\", f000358, f000743);\n  private static final Expr f000745 =\n      Expr.makeTextLiteral(new String[] {\"\\\"\", \"\\\": \", \"\"}, new Expr[] {f000563, f000730});\n  private static final Expr f000746 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000745),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000360)\n          });\n  private static final Expr f000747 = Expr.makeLambda(\"line\", f000226, f000746);\n  private static final Expr f000748 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Complex\", f000744),\n            new SimpleImmutableEntry<String, Expr>(\"Simple\", f000747)\n          });\n  private static final Expr f000749 = Expr.makeMerge(f000748, f000294, null);\n  private static final Expr f000750 = Expr.makeNonEmptyListLiteral(new Expr[] {f000749});\n  private static final Expr f000751 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000750, f000248);\n  private static final Expr f000752 = Expr.makeLambda(\"as\", f000373, f000751);\n  private static final Expr f000753 = Expr.makeLambda(\"x\", f000555, f000752);\n  private static final Expr f000754 =\n      Expr.makeApplication(f000000, new Expr[] {f000555, f000372, f000373, f000753, f000379});\n  private static final Expr f000755 =\n      Expr.makeApplication(f000000, new Expr[] {f000358, f000754, f000357, f000477, f000360});\n  private static final Expr f000756 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000737, f000755);\n  private static final Expr f000757 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000736),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000756)\n          });\n  private static final Expr f000758 = Expr.makeApplication(f000368, new Expr[] {f000757});\n  private static final Expr f000759 = Expr.makeLambda(\"inputs\", f000610, f000758);\n  private static final Expr f000760 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000525),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000759)\n          });\n  private static final Expr f000761 = Expr.makeMerge(f000760, f000624, null);\n  private static final Expr f000762 = Expr.makeLambda(\"inputs\", f000609, f000761);\n  private static final Expr f000763 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"array\", f000723),\n            new SimpleImmutableEntry<String, Expr>(\"bool\", f000512),\n            new SimpleImmutableEntry<String, Expr>(\"double\", f000515),\n            new SimpleImmutableEntry<String, Expr>(\"integer\", f000521),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000523),\n            new SimpleImmutableEntry<String, Expr>(\"object\", f000762),\n            new SimpleImmutableEntry<String, Expr>(\"string\", f000636)\n          });\n  private static final Expr f000764 = Expr.makeApplication(f000244, new Expr[] {f000364, f000763});\n  private static final Expr f000765 = Expr.makeMerge(f000363, f000764, null);\n  private static final Expr f000766 = Expr.makeFieldAccess(f000765, \"head\");\n  private static final Expr f000767 = Expr.makeNonEmptyListLiteral(new Expr[] {f000766});\n  private static final Expr f000768 = Expr.makeFieldAccess(f000765, \"tail\");\n  private static final Expr f000769 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000767, f000768);\n  private static final Expr f000770 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000769, f000226, f000646, f000647});\n  private static final Expr f000771 = Expr.makeLambda(\"json\", f000243, f000770);\n  private static final Expr f000772 = Expr.makeLambda(\"json\", f000241, f000348);\n  private static final Expr f000773 = Expr.makeLambda(\"JSON\", f000019, f000772);\n  private static final Expr f000774 = Expr.makeLambda(\"x\", f000226, f000773);\n  private static final Expr f000775 = Expr.makeIdentifier(\"contents\", 0);\n  private static final Expr f000776 = Expr.makeIdentifier(\"tagFieldName\", 0);\n  private static final Expr f000777 = Expr.makeFieldAccess(f000227, \"Inline\");\n  private static final Expr f000778 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"contents\", f000775),\n            new SimpleImmutableEntry<String, Expr>(\"field\", f000776),\n            new SimpleImmutableEntry<String, Expr>(\"nesting\", f000777)\n          });\n  private static final Expr f000779 = Expr.makeLambda(\"contents\", f000070, f000778);\n  private static final Expr f000780 = Expr.makeLambda(\"a\", f000019, f000779);\n  private static final Expr f000781 = Expr.makeLambda(\"tagFieldName\", f000226, f000780);\n  private static final Expr f000782 = Expr.makeFieldAccess(f000227, \"Nested\");\n  private static final Expr f000783 = Expr.makeIdentifier(\"contentsFieldName\", 0);\n  private static final Expr f000784 = Expr.makeApplication(f000782, new Expr[] {f000783});\n  private static final Expr f000785 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"contents\", f000775),\n            new SimpleImmutableEntry<String, Expr>(\"field\", f000776),\n            new SimpleImmutableEntry<String, Expr>(\"nesting\", f000784)\n          });\n  private static final Expr f000786 = Expr.makeLambda(\"contents\", f000070, f000785);\n  private static final Expr f000787 = Expr.makeLambda(\"a\", f000019, f000786);\n  private static final Expr f000788 = Expr.makeLambda(\"tagFieldName\", f000226, f000787);\n  private static final Expr f000789 = Expr.makeLambda(\"contentsFieldName\", f000226, f000788);\n  private static final Expr f000790 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Nesting\", f000227),\n            new SimpleImmutableEntry<String, Expr>(\"Tagged\", f000229),\n            new SimpleImmutableEntry<String, Expr>(\"Type\", f000243),\n            new SimpleImmutableEntry<String, Expr>(\"array\", f000258),\n            new SimpleImmutableEntry<String, Expr>(\"bool\", f000263),\n            new SimpleImmutableEntry<String, Expr>(\"double\", f000268),\n            new SimpleImmutableEntry<String, Expr>(\"integer\", f000273),\n            new SimpleImmutableEntry<String, Expr>(\"keyText\", f000278),\n            new SimpleImmutableEntry<String, Expr>(\"keyValue\", f000282),\n            new SimpleImmutableEntry<String, Expr>(\"natural\", f000287),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000290),\n            new SimpleImmutableEntry<String, Expr>(\"number\", f000268),\n            new SimpleImmutableEntry<String, Expr>(\"object\", f000307),\n            new SimpleImmutableEntry<String, Expr>(\"omitNullFields\", f000356),\n            new SimpleImmutableEntry<String, Expr>(\"render\", f000649),\n            new SimpleImmutableEntry<String, Expr>(\"renderCompact\", f000700),\n            new SimpleImmutableEntry<String, Expr>(\"renderInteger\", f000680),\n            new SimpleImmutableEntry<String, Expr>(\"renderYAML\", f000771),\n            new SimpleImmutableEntry<String, Expr>(\"string\", f000774),\n            new SimpleImmutableEntry<String, Expr>(\"tagInline\", f000781),\n            new SimpleImmutableEntry<String, Expr>(\"tagNested\", f000789)\n          });\n  private static final Expr f000791 = Expr.makeOperatorApplication(Operator.AND, f000057, f000004);\n  private static final Expr f000792 = Expr.makeLambda(\"r\", f000001, f000791);\n  private static final Expr f000793 = Expr.makeLambda(\"x\", f000070, f000792);\n  private static final Expr f000794 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000001, f000793, f000008});\n  private static final Expr f000795 = Expr.makeApplication(f000010, new Expr[] {f000070});\n  private static final Expr f000796 = Expr.makeLambda(\"xs\", f000795, f000794);\n  private static final Expr f000797 = Expr.makePi(\"_\", f000070, f000001);\n  private static final Expr f000798 = Expr.makeLambda(\"f\", f000797, f000796);\n  private static final Expr f000799 = Expr.makeLambda(\"a\", f000019, f000798);\n  private static final Expr f000800 = Expr.makeOperatorApplication(Operator.OR, f000057, f000004);\n  private static final Expr f000801 = Expr.makeLambda(\"r\", f000001, f000800);\n  private static final Expr f000802 = Expr.makeLambda(\"x\", f000070, f000801);\n  private static final Expr f000803 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000001, f000802, f000014});\n  private static final Expr f000804 = Expr.makeLambda(\"xs\", f000795, f000803);\n  private static final Expr f000805 = Expr.makeLambda(\"f\", f000797, f000804);\n  private static final Expr f000806 = Expr.makeLambda(\"a\", f000019, f000805);\n  private static final Expr f000807 = Expr.makeBuiltIn(\"List/build\");\n  private static final Expr f000808 = Expr.makeIdentifier(\"xss\", 0);\n  private static final Expr f000809 = Expr.makeIdentifier(\"a\", 1);\n  private static final Expr f000810 = Expr.makeApplication(f000010, new Expr[] {f000809});\n  private static final Expr f000811 = Expr.makeLambda(\"as\", f000810, f000337);\n  private static final Expr f000812 = Expr.makeLambda(\"a\", f000070, f000811);\n  private static final Expr f000813 = Expr.makeIdentifier(\"ys\", 0);\n  private static final Expr f000814 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000795, f000812, f000813});\n  private static final Expr f000815 = Expr.makeLambda(\"ys\", f000795, f000814);\n  private static final Expr f000816 = Expr.makeLambda(\"xs\", f000795, f000815);\n  private static final Expr f000817 = Expr.makeEmptyListLiteral(f000795);\n  private static final Expr f000818 =\n      Expr.makeApplication(f000000, new Expr[] {f000795, f000808, f000795, f000816, f000817});\n  private static final Expr f000819 = Expr.makeApplication(f000010, new Expr[] {f000795});\n  private static final Expr f000820 = Expr.makeLambda(\"xss\", f000819, f000818);\n  private static final Expr f000821 = Expr.makeLambda(\"a\", f000019, f000820);\n  private static final Expr f000822 = Expr.makeApplication(f000010, new Expr[] {f000029});\n  private static final Expr f000823 = Expr.makeLambda(\"as\", f000822, f000337);\n  private static final Expr f000824 = Expr.makeLambda(\"a\", f000029, f000823);\n  private static final Expr f000825 =\n      Expr.makeApplication(f000000, new Expr[] {f000029, f000057, f000822, f000824});\n  private static final Expr f000826 = Expr.makeLambda(\"x\", f000070, f000825);\n  private static final Expr f000827 = Expr.makeEmptyListLiteral(f000822);\n  private static final Expr f000828 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000822, f000826, f000827});\n  private static final Expr f000829 = Expr.makeLambda(\"xs\", f000795, f000828);\n  private static final Expr f000830 = Expr.makePi(\"_\", f000070, f000822);\n  private static final Expr f000831 = Expr.makeLambda(\"f\", f000830, f000829);\n  private static final Expr f000832 = Expr.makeLambda(\"b\", f000019, f000831);\n  private static final Expr f000833 = Expr.makeLambda(\"a\", f000019, f000832);\n  private static final Expr f000834 = Expr.makeLambda(\"l\", f000795, f000003);\n  private static final Expr f000835 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000817),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000834)\n          });\n  private static final Expr f000836 = Expr.makeIdentifier(\"o\", 0);\n  private static final Expr f000837 = Expr.makeMerge(f000835, f000836, null);\n  private static final Expr f000838 = Expr.makeApplication(f000396, new Expr[] {f000795});\n  private static final Expr f000839 = Expr.makeLambda(\"o\", f000838, f000837);\n  private static final Expr f000840 = Expr.makeLambda(\"a\", f000019, f000839);\n  private static final Expr f000841 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"index\", f000221),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000070)\n          });\n  private static final Expr f000842 = Expr.makeBuiltIn(\"List/indexed\");\n  private static final Expr f000843 = Expr.makeApplication(f000842, new Expr[] {f000070, f000002});\n  private static final Expr f000844 = Expr.makeFieldAccess(f000022, \"index\");\n  private static final Expr f000845 = Expr.makeApplication(f000089, new Expr[] {f000844, f000076});\n  private static final Expr f000846 = Expr.makeApplication(f000074, new Expr[] {f000845});\n  private static final Expr f000847 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000311, f000002);\n  private static final Expr f000848 = Expr.makeIf(f000846, f000847, f000002);\n  private static final Expr f000849 = Expr.makeLambda(\"xs\", f000795, f000848);\n  private static final Expr f000850 = Expr.makeLambda(\"x\", f000841, f000849);\n  private static final Expr f000851 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f000843, f000795, f000850, f000817});\n  private static final Expr f000852 = Expr.makeLambda(\"xs\", f000795, f000851);\n  private static final Expr f000853 = Expr.makeLambda(\"a\", f000019, f000852);\n  private static final Expr f000854 = Expr.makeLambda(\"n\", f000221, f000853);\n  private static final Expr f000855 = Expr.makeLambda(\"a\", f000019, f000817);\n  private static final Expr f000856 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000401, f000002);\n  private static final Expr f000857 = Expr.makeIf(f000057, f000856, f000002);\n  private static final Expr f000858 = Expr.makeLambda(\"xs\", f000795, f000857);\n  private static final Expr f000859 = Expr.makeLambda(\"x\", f000070, f000858);\n  private static final Expr f000860 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000795, f000859, f000817});\n  private static final Expr f000861 = Expr.makeLambda(\"xs\", f000795, f000860);\n  private static final Expr f000862 = Expr.makeLambda(\"f\", f000797, f000861);\n  private static final Expr f000863 = Expr.makeLambda(\"a\", f000019, f000862);\n  private static final Expr f000864 = Expr.makeIdentifier(\"list\", 0);\n  private static final Expr f000865 = Expr.makePi(\"_\", f000864, f000864);\n  private static final Expr f000866 = Expr.makeIdentifier(\"cons\", 0);\n  private static final Expr f000867 = Expr.makeApplication(f000866, new Expr[] {f000003, f000022});\n  private static final Expr f000868 = Expr.makeApplication(f000013, new Expr[] {f000867});\n  private static final Expr f000869 = Expr.makeLambda(\"l\", f000864, f000868);\n  private static final Expr f000870 = Expr.makeLambda(\"f\", f000865, f000869);\n  private static final Expr f000871 = Expr.makeLambda(\"x\", f000070, f000870);\n  private static final Expr f000872 = Expr.makeLambda(\"l\", f000864, f000003);\n  private static final Expr f000873 = Expr.makeIdentifier(\"nil\", 0);\n  private static final Expr f000874 =\n      Expr.makeApplication(\n          f000000, new Expr[] {f000070, f000002, f000865, f000871, f000872, f000873});\n  private static final Expr f000875 = Expr.makeLambda(\"nil\", f000864, f000874);\n  private static final Expr f000876 = Expr.makePi(\"_\", f000070, f000864);\n  private static final Expr f000877 = Expr.makePi(\"_\", f000864, f000876);\n  private static final Expr f000878 = Expr.makeLambda(\"cons\", f000877, f000875);\n  private static final Expr f000879 = Expr.makeLambda(\"list\", f000019, f000878);\n  private static final Expr f000880 = Expr.makeLambda(\"xs\", f000795, f000879);\n  private static final Expr f000881 = Expr.makeLambda(\"a\", f000019, f000880);\n  private static final Expr f000882 = Expr.Constants.EMPTY_RECORD_TYPE;\n  private static final Expr f000883 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"index\", f000221),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000882)\n          });\n  private static final Expr f000884 = Expr.makeBuiltIn(\"Natural/fold\");\n  private static final Expr f000885 = Expr.makeApplication(f000010, new Expr[] {f000882});\n  private static final Expr f000886 = Expr.Constants.EMPTY_RECORD_LITERAL;\n  private static final Expr f000887 = Expr.makeNonEmptyListLiteral(new Expr[] {f000886});\n  private static final Expr f000888 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000887, f000248);\n  private static final Expr f000889 = Expr.makeLambda(\"as\", f000885, f000888);\n  private static final Expr f000890 = Expr.makeEmptyListLiteral(f000885);\n  private static final Expr f000891 =\n      Expr.makeApplication(f000884, new Expr[] {f000076, f000885, f000889, f000890});\n  private static final Expr f000892 = Expr.makeApplication(f000842, new Expr[] {f000882, f000891});\n  private static final Expr f000893 = Expr.makeApplication(f000013, new Expr[] {f000844});\n  private static final Expr f000894 = Expr.makeNonEmptyListLiteral(new Expr[] {f000893});\n  private static final Expr f000895 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000894, f000248);\n  private static final Expr f000896 = Expr.makeLambda(\"as\", f000795, f000895);\n  private static final Expr f000897 = Expr.makeLambda(\"x\", f000883, f000896);\n  private static final Expr f000898 =\n      Expr.makeApplication(f000000, new Expr[] {f000883, f000892, f000795, f000897, f000817});\n  private static final Expr f000899 = Expr.makePi(\"_\", f000221, f000070);\n  private static final Expr f000900 = Expr.makeLambda(\"f\", f000899, f000898);\n  private static final Expr f000901 = Expr.makeLambda(\"a\", f000019, f000900);\n  private static final Expr f000902 = Expr.makeLambda(\"n\", f000221, f000901);\n  private static final Expr f000903 = Expr.makeBuiltIn(\"List/head\");\n  private static final Expr f000904 = Expr.makeApplication(f000903, new Expr[] {f000070, f000851});\n  private static final Expr f000905 = Expr.makeLambda(\"xs\", f000795, f000904);\n  private static final Expr f000906 = Expr.makeLambda(\"a\", f000019, f000905);\n  private static final Expr f000907 = Expr.makeLambda(\"n\", f000221, f000906);\n  private static final Expr f000908 = Expr.makeFieldAccess(f000023, \"index\");\n  private static final Expr f000909 =\n      Expr.makeApplication(f000884, new Expr[] {f000908, f000070, f000013, f000022});\n  private static final Expr f000910 = Expr.makeNonEmptyListLiteral(new Expr[] {f000909});\n  private static final Expr f000911 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000910, f000248);\n  private static final Expr f000912 = Expr.makeLambda(\"as\", f000795, f000911);\n  private static final Expr f000913 = Expr.makeLambda(\"y\", f000883, f000912);\n  private static final Expr f000914 =\n      Expr.makeApplication(f000000, new Expr[] {f000883, f000892, f000795, f000913, f000817});\n  private static final Expr f000915 = Expr.makeLambda(\"x\", f000070, f000914);\n  private static final Expr f000916 = Expr.makePi(\"_\", f000070, f000070);\n  private static final Expr f000917 = Expr.makeLambda(\"f\", f000916, f000915);\n  private static final Expr f000918 = Expr.makeLambda(\"a\", f000019, f000917);\n  private static final Expr f000919 = Expr.makeLambda(\"n\", f000221, f000918);\n  private static final Expr f000920 = Expr.makeBuiltIn(\"List/last\");\n  private static final Expr f000921 = Expr.makeBuiltIn(\"List/length\");\n  private static final Expr f000922 = Expr.makeNonEmptyListLiteral(new Expr[] {f000057});\n  private static final Expr f000923 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000922, f000248);\n  private static final Expr f000924 = Expr.makeLambda(\"as\", f000822, f000923);\n  private static final Expr f000925 = Expr.makeLambda(\"x\", f000070, f000924);\n  private static final Expr f000926 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000822, f000925, f000827});\n  private static final Expr f000927 = Expr.makeLambda(\"xs\", f000795, f000926);\n  private static final Expr f000928 = Expr.makePi(\"_\", f000070, f000029);\n  private static final Expr f000929 = Expr.makeLambda(\"f\", f000928, f000927);\n  private static final Expr f000930 = Expr.makeLambda(\"b\", f000019, f000929);\n  private static final Expr f000931 = Expr.makeLambda(\"a\", f000019, f000930);\n  private static final Expr f000932 = Expr.makeApplication(f000921, new Expr[] {f000070, f000002});\n  private static final Expr f000933 = Expr.makeApplication(f000074, new Expr[] {f000932});\n  private static final Expr f000934 = Expr.makeLambda(\"xs\", f000795, f000933);\n  private static final Expr f000935 = Expr.makeLambda(\"a\", f000019, f000934);\n  private static final Expr f000936 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"false\", f000795),\n            new SimpleImmutableEntry<String, Expr>(\"true\", f000795)\n          });\n  private static final Expr f000937 = Expr.makeIdentifier(\"p\", 0);\n  private static final Expr f000938 = Expr.makeFieldAccess(f000937, \"false\");\n  private static final Expr f000939 = Expr.makeFieldAccess(f000937, \"true\");\n  private static final Expr f000940 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000401, f000939);\n  private static final Expr f000941 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"false\", f000938),\n            new SimpleImmutableEntry<String, Expr>(\"true\", f000940)\n          });\n  private static final Expr f000942 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000401, f000938);\n  private static final Expr f000943 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"false\", f000942),\n            new SimpleImmutableEntry<String, Expr>(\"true\", f000939)\n          });\n  private static final Expr f000944 = Expr.makeIf(f000057, f000941, f000943);\n  private static final Expr f000945 = Expr.makeLambda(\"p\", f000936, f000944);\n  private static final Expr f000946 = Expr.makeLambda(\"x\", f000070, f000945);\n  private static final Expr f000947 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"false\", f000817),\n            new SimpleImmutableEntry<String, Expr>(\"true\", f000817)\n          });\n  private static final Expr f000948 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000936, f000946, f000947});\n  private static final Expr f000949 = Expr.makeLambda(\"xs\", f000795, f000948);\n  private static final Expr f000950 = Expr.makeLambda(\"f\", f000797, f000949);\n  private static final Expr f000951 = Expr.makeLambda(\"a\", f000019, f000950);\n  private static final Expr f000952 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000401, f000248);\n  private static final Expr f000953 = Expr.makeLambda(\"as\", f000795, f000952);\n  private static final Expr f000954 =\n      Expr.makeApplication(f000884, new Expr[] {f000076, f000795, f000953, f000817});\n  private static final Expr f000955 = Expr.makeLambda(\"x\", f000070, f000954);\n  private static final Expr f000956 = Expr.makeLambda(\"a\", f000019, f000955);\n  private static final Expr f000957 = Expr.makeLambda(\"n\", f000221, f000956);\n  private static final Expr f000958 = Expr.makeApplication(f000010, new Expr[] {f000841});\n  private static final Expr f000959 = Expr.makeIdentifier(\"kvss\", 0);\n  private static final Expr f000960 = Expr.makePi(\"_\", f000221, f000958);\n  private static final Expr f000961 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"count\", f000221),\n            new SimpleImmutableEntry<String, Expr>(\"diff\", f000960)\n          });\n  private static final Expr f000962 = Expr.makeFieldAccess(f000023, \"count\");\n  private static final Expr f000963 = Expr.makeIdentifier(\"kvs\", 0);\n  private static final Expr f000964 = Expr.makeApplication(f000921, new Expr[] {f000841, f000963});\n  private static final Expr f000965 = Expr.makeOperatorApplication(Operator.PLUS, f000962, f000964);\n  private static final Expr f000966 = Expr.makeIdentifier(\"kvOld\", 0);\n  private static final Expr f000967 = Expr.makeFieldAccess(f000966, \"index\");\n  private static final Expr f000968 = Expr.makeOperatorApplication(Operator.PLUS, f000967, f000076);\n  private static final Expr f000969 = Expr.makeFieldAccess(f000966, \"value\");\n  private static final Expr f000970 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"index\", f000968),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000969)\n          });\n  private static final Expr f000971 = Expr.makeNonEmptyListLiteral(new Expr[] {f000970});\n  private static final Expr f000972 = Expr.makeIdentifier(\"z\", 0);\n  private static final Expr f000973 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000971, f000972);\n  private static final Expr f000974 = Expr.makeLambda(\"z\", f000958, f000973);\n  private static final Expr f000975 = Expr.makeLambda(\"kvOld\", f000841, f000974);\n  private static final Expr f000976 = Expr.makeFieldAccess(f000023, \"diff\");\n  private static final Expr f000977 = Expr.makeOperatorApplication(Operator.PLUS, f000076, f000964);\n  private static final Expr f000978 = Expr.makeApplication(f000976, new Expr[] {f000977});\n  private static final Expr f000979 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f000963, f000958, f000975, f000978});\n  private static final Expr f000980 = Expr.makeLambda(\"n\", f000221, f000979);\n  private static final Expr f000981 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"count\", f000965),\n            new SimpleImmutableEntry<String, Expr>(\"diff\", f000980)\n          });\n  private static final Expr f000982 = Expr.makeLambda(\"y\", f000961, f000981);\n  private static final Expr f000983 = Expr.makeLambda(\"kvs\", f000958, f000982);\n  private static final Expr f000984 = Expr.makeNaturalLiteral(new BigInteger(\"0\"));\n  private static final Expr f000985 = Expr.makeEmptyListLiteral(f000958);\n  private static final Expr f000986 = Expr.makeLambda(\"_\", f000221, f000985);\n  private static final Expr f000987 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"count\", f000984),\n            new SimpleImmutableEntry<String, Expr>(\"diff\", f000986)\n          });\n  private static final Expr f000988 =\n      Expr.makeApplication(f000000, new Expr[] {f000958, f000959, f000961, f000983, f000987});\n  private static final Expr f000989 = Expr.makeFieldAccess(f000988, \"diff\");\n  private static final Expr f000990 = Expr.makeApplication(f000989, new Expr[] {f000984});\n  private static final Expr f000991 = Expr.makeApplication(f000010, new Expr[] {f000958});\n  private static final Expr f000992 = Expr.makeLambda(\"kvss\", f000991, f000990);\n  private static final Expr f000993 = Expr.makeLambda(\"a\", f000019, f000992);\n  private static final Expr f000994 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000846, f000014);\n  private static final Expr f000995 = Expr.makeIf(f000994, f000847, f000002);\n  private static final Expr f000996 = Expr.makeLambda(\"xs\", f000795, f000995);\n  private static final Expr f000997 = Expr.makeLambda(\"x\", f000841, f000996);\n  private static final Expr f000998 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f000843, f000795, f000997, f000817});\n  private static final Expr f000999 = Expr.makeLambda(\"xs\", f000795, f000998);\n  private static final Expr f001000 = Expr.makeLambda(\"a\", f000019, f000999);\n  private static final Expr f001001 = Expr.makeLambda(\"n\", f000221, f001000);\n  private static final Expr f001002 = Expr.makeApplication(f000396, new Expr[] {f000070});\n  private static final Expr f001003 = Expr.makeLambda(\"x\", f000070, f000401);\n  private static final Expr f001004 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000817),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001003)\n          });\n  private static final Expr f001005 = Expr.makeMerge(f001004, f000022, null);\n  private static final Expr f001006 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f001005, f000795, f000812});\n  private static final Expr f001007 = Expr.makeLambda(\"x\", f001002, f001006);\n  private static final Expr f001008 =\n      Expr.makeApplication(f000000, new Expr[] {f001002, f000002, f000795, f001007, f000817});\n  private static final Expr f001009 = Expr.makeApplication(f000010, new Expr[] {f001002});\n  private static final Expr f001010 = Expr.makeLambda(\"xs\", f001009, f001008);\n  private static final Expr f001011 = Expr.makeLambda(\"a\", f000019, f001010);\n  private static final Expr f001012 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"_1\", f000070),\n            new SimpleImmutableEntry<String, Expr>(\"_2\", f000029)\n          });\n  private static final Expr f001013 = Expr.makeFieldAccess(f000022, \"_1\");\n  private static final Expr f001014 = Expr.makeNonEmptyListLiteral(new Expr[] {f001013});\n  private static final Expr f001015 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001014, f000248);\n  private static final Expr f001016 = Expr.makeLambda(\"as\", f000795, f001015);\n  private static final Expr f001017 = Expr.makeLambda(\"x\", f001012, f001016);\n  private static final Expr f001018 =\n      Expr.makeApplication(f000000, new Expr[] {f001012, f000002, f000795, f001017, f000817});\n  private static final Expr f001019 = Expr.makeFieldAccess(f000022, \"_2\");\n  private static final Expr f001020 = Expr.makeNonEmptyListLiteral(new Expr[] {f001019});\n  private static final Expr f001021 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001020, f000248);\n  private static final Expr f001022 = Expr.makeLambda(\"as\", f000822, f001021);\n  private static final Expr f001023 = Expr.makeLambda(\"x\", f001012, f001022);\n  private static final Expr f001024 =\n      Expr.makeApplication(f000000, new Expr[] {f001012, f000002, f000822, f001023, f000827});\n  private static final Expr f001025 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"_1\", f001018),\n            new SimpleImmutableEntry<String, Expr>(\"_2\", f001024)\n          });\n  private static final Expr f001026 = Expr.makeApplication(f000010, new Expr[] {f001012});\n  private static final Expr f001027 = Expr.makeLambda(\"xs\", f001026, f001025);\n  private static final Expr f001028 = Expr.makeLambda(\"b\", f000019, f001027);\n  private static final Expr f001029 = Expr.makeLambda(\"a\", f000019, f001028);\n  private static final Expr f001030 = Expr.makeIdentifier(\"rest\", 0);\n  private static final Expr f001031 = Expr.makeIdentifier(\"ix\", 0);\n  private static final Expr f001032 = Expr.makeFieldAccess(f001031, \"value\");\n  private static final Expr f001033 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"_1\", f001032),\n            new SimpleImmutableEntry<String, Expr>(\"_2\", f000023)\n          });\n  private static final Expr f001034 = Expr.makeNonEmptyListLiteral(new Expr[] {f001033});\n  private static final Expr f001035 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001034, f001030);\n  private static final Expr f001036 = Expr.makeLambda(\"y\", f000029, f001035);\n  private static final Expr f001037 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001030),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001036)\n          });\n  private static final Expr f001038 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"index\", f000221),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000029)\n          });\n  private static final Expr f001039 = Expr.makeApplication(f000842, new Expr[] {f000029, f000813});\n  private static final Expr f001040 = Expr.makeFieldAccess(f001031, \"index\");\n  private static final Expr f001041 = Expr.makeApplication(f000089, new Expr[] {f000844, f001040});\n  private static final Expr f001042 = Expr.makeApplication(f000074, new Expr[] {f001041});\n  private static final Expr f001043 = Expr.makeIf(f001042, f000847, f000002);\n  private static final Expr f001044 = Expr.makeLambda(\"xs\", f000822, f001043);\n  private static final Expr f001045 = Expr.makeLambda(\"x\", f001038, f001044);\n  private static final Expr f001046 =\n      Expr.makeApplication(f000000, new Expr[] {f001038, f001039, f000822, f001045, f000827});\n  private static final Expr f001047 = Expr.makeApplication(f000903, new Expr[] {f000029, f001046});\n  private static final Expr f001048 = Expr.makeMerge(f001037, f001047, null);\n  private static final Expr f001049 = Expr.makeLambda(\"rest\", f001026, f001048);\n  private static final Expr f001050 = Expr.makeLambda(\"ix\", f000841, f001049);\n  private static final Expr f001051 = Expr.makeEmptyListLiteral(f001026);\n  private static final Expr f001052 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f000843, f001026, f001050, f001051});\n  private static final Expr f001053 = Expr.makeLambda(\"ys\", f000822, f001052);\n  private static final Expr f001054 = Expr.makeLambda(\"b\", f000019, f001053);\n  private static final Expr f001055 = Expr.makeLambda(\"xs\", f000795, f001054);\n  private static final Expr f001056 = Expr.makeLambda(\"a\", f000019, f001055);\n  private static final Expr f001057 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"all\", f000799),\n            new SimpleImmutableEntry<String, Expr>(\"any\", f000806),\n            new SimpleImmutableEntry<String, Expr>(\"build\", f000807),\n            new SimpleImmutableEntry<String, Expr>(\"concat\", f000821),\n            new SimpleImmutableEntry<String, Expr>(\"concatMap\", f000833),\n            new SimpleImmutableEntry<String, Expr>(\"default\", f000840),\n            new SimpleImmutableEntry<String, Expr>(\"drop\", f000854),\n            new SimpleImmutableEntry<String, Expr>(\"empty\", f000855),\n            new SimpleImmutableEntry<String, Expr>(\"filter\", f000863),\n            new SimpleImmutableEntry<String, Expr>(\"fold\", f000000),\n            new SimpleImmutableEntry<String, Expr>(\"foldLeft\", f000881),\n            new SimpleImmutableEntry<String, Expr>(\"generate\", f000902),\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000903),\n            new SimpleImmutableEntry<String, Expr>(\"index\", f000907),\n            new SimpleImmutableEntry<String, Expr>(\"indexed\", f000842),\n            new SimpleImmutableEntry<String, Expr>(\"iterate\", f000919),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f000920),\n            new SimpleImmutableEntry<String, Expr>(\"length\", f000921),\n            new SimpleImmutableEntry<String, Expr>(\"map\", f000931),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f000935),\n            new SimpleImmutableEntry<String, Expr>(\"partition\", f000951),\n            new SimpleImmutableEntry<String, Expr>(\"replicate\", f000957),\n            new SimpleImmutableEntry<String, Expr>(\"reverse\", f000487),\n            new SimpleImmutableEntry<String, Expr>(\"shifted\", f000993),\n            new SimpleImmutableEntry<String, Expr>(\"take\", f001001),\n            new SimpleImmutableEntry<String, Expr>(\"unpackOptionals\", f001011),\n            new SimpleImmutableEntry<String, Expr>(\"unzip\", f001029),\n            new SimpleImmutableEntry<String, Expr>(\"zip\", f001056)\n          });\n  private static final Expr f001058 =\n      Expr.makeUnionType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Environment\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"Local\", f000226),\n            new SimpleImmutableEntry<String, Expr>(\"Missing\", null),\n            new SimpleImmutableEntry<String, Expr>(\"Remote\", f000226)\n          });\n  private static final Expr f001059 =\n      Expr.makeRecordLiteral(new Entry[] {new SimpleImmutableEntry<String, Expr>(\"Type\", f001058)});\n  private static final Expr f001060 = Expr.makeIdentifier(\"k\", 0);\n  private static final Expr f001061 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f001060),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000279)\n          });\n  private static final Expr f001062 = Expr.makeLambda(\"v\", f000019, f001061);\n  private static final Expr f001063 = Expr.makeLambda(\"k\", f000019, f001062);\n  private static final Expr f001064 = Expr.makeApplication(f000010, new Expr[] {f001061});\n  private static final Expr f001065 = Expr.makeLambda(\"v\", f000019, f001064);\n  private static final Expr f001066 = Expr.makeLambda(\"k\", f000019, f001065);\n  private static final Expr f001067 = Expr.makeEmptyListLiteral(f001064);\n  private static final Expr f001068 = Expr.makeLambda(\"v\", f000019, f001067);\n  private static final Expr f001069 = Expr.makeLambda(\"k\", f000019, f001068);\n  private static final Expr f001070 = Expr.makeApplication(f000010, new Expr[] {f001060});\n  private static final Expr f001071 = Expr.makeNonEmptyListLiteral(new Expr[] {f000293});\n  private static final Expr f001072 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001071, f000248);\n  private static final Expr f001073 = Expr.makeLambda(\"as\", f001070, f001072);\n  private static final Expr f001074 = Expr.makeLambda(\"x\", f001061, f001073);\n  private static final Expr f001075 = Expr.makeEmptyListLiteral(f001070);\n  private static final Expr f001076 =\n      Expr.makeApplication(f000000, new Expr[] {f001061, f000002, f001070, f001074, f001075});\n  private static final Expr f001077 = Expr.makeLambda(\"xs\", f001064, f001076);\n  private static final Expr f001078 = Expr.makeLambda(\"v\", f000019, f001077);\n  private static final Expr f001079 = Expr.makeLambda(\"k\", f000019, f001078);\n  private static final Expr f001080 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f001060),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000070)\n          });\n  private static final Expr f001081 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f001060),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000029)\n          });\n  private static final Expr f001082 = Expr.makeApplication(f000010, new Expr[] {f001081});\n  private static final Expr f001083 = Expr.makeApplication(f000013, new Expr[] {f000294});\n  private static final Expr f001084 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000293),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f001083)\n          });\n  private static final Expr f001085 = Expr.makeNonEmptyListLiteral(new Expr[] {f001084});\n  private static final Expr f001086 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001085, f000248);\n  private static final Expr f001087 = Expr.makeLambda(\"as\", f001082, f001086);\n  private static final Expr f001088 = Expr.makeLambda(\"x\", f001080, f001087);\n  private static final Expr f001089 = Expr.makeEmptyListLiteral(f001082);\n  private static final Expr f001090 =\n      Expr.makeApplication(f000000, new Expr[] {f001080, f000085, f001082, f001088, f001089});\n  private static final Expr f001091 = Expr.makeApplication(f000010, new Expr[] {f001080});\n  private static final Expr f001092 = Expr.makeLambda(\"m\", f001091, f001090);\n  private static final Expr f001093 = Expr.makeLambda(\"f\", f000928, f001092);\n  private static final Expr f001094 = Expr.makeLambda(\"b\", f000019, f001093);\n  private static final Expr f001095 = Expr.makeLambda(\"a\", f000019, f001094);\n  private static final Expr f001096 = Expr.makeLambda(\"k\", f000019, f001095);\n  private static final Expr f001097 = Expr.makeApplication(f000396, new Expr[] {f000279});\n  private static final Expr f001098 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f001060),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f001097)\n          });\n  private static final Expr f001099 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"mapKey\", f000293),\n            new SimpleImmutableEntry<String, Expr>(\"mapValue\", f000279)\n          });\n  private static final Expr f001100 = Expr.makeNonEmptyListLiteral(new Expr[] {f001099});\n  private static final Expr f001101 = Expr.makeLambda(\"v\", f000279, f001100);\n  private static final Expr f001102 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001067),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001101)\n          });\n  private static final Expr f001103 = Expr.makeMerge(f001102, f000294, null);\n  private static final Expr f001104 = Expr.makeLambda(\"as\", f001064, f000337);\n  private static final Expr f001105 = Expr.makeLambda(\"a\", f001061, f001104);\n  private static final Expr f001106 =\n      Expr.makeApplication(f000000, new Expr[] {f001061, f001103, f001064, f001105});\n  private static final Expr f001107 = Expr.makeLambda(\"x\", f001098, f001106);\n  private static final Expr f001108 =\n      Expr.makeApplication(f000000, new Expr[] {f001098, f000002, f001064, f001107, f001067});\n  private static final Expr f001109 = Expr.makeApplication(f000010, new Expr[] {f001098});\n  private static final Expr f001110 = Expr.makeLambda(\"xs\", f001109, f001108);\n  private static final Expr f001111 = Expr.makeLambda(\"v\", f000019, f001110);\n  private static final Expr f001112 = Expr.makeLambda(\"k\", f000019, f001111);\n  private static final Expr f001113 = Expr.makeApplication(f000010, new Expr[] {f000279});\n  private static final Expr f001114 = Expr.makeNonEmptyListLiteral(new Expr[] {f000294});\n  private static final Expr f001115 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001114, f000248);\n  private static final Expr f001116 = Expr.makeLambda(\"as\", f001113, f001115);\n  private static final Expr f001117 = Expr.makeLambda(\"x\", f001061, f001116);\n  private static final Expr f001118 = Expr.makeEmptyListLiteral(f001113);\n  private static final Expr f001119 =\n      Expr.makeApplication(f000000, new Expr[] {f001061, f000002, f001113, f001117, f001118});\n  private static final Expr f001120 = Expr.makeLambda(\"xs\", f001064, f001119);\n  private static final Expr f001121 = Expr.makeLambda(\"v\", f000019, f001120);\n  private static final Expr f001122 = Expr.makeLambda(\"k\", f000019, f001121);\n  private static final Expr f001123 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Entry\", f001063),\n            new SimpleImmutableEntry<String, Expr>(\"Type\", f001066),\n            new SimpleImmutableEntry<String, Expr>(\"empty\", f001069),\n            new SimpleImmutableEntry<String, Expr>(\"keyText\", f000278),\n            new SimpleImmutableEntry<String, Expr>(\"keyValue\", f000282),\n            new SimpleImmutableEntry<String, Expr>(\"keys\", f001079),\n            new SimpleImmutableEntry<String, Expr>(\"map\", f001096),\n            new SimpleImmutableEntry<String, Expr>(\"unpackOptionals\", f001112),\n            new SimpleImmutableEntry<String, Expr>(\"values\", f001122)\n          });\n  private static final Expr f001124 = Expr.makeApplication(f000010, new Expr[] {f000085});\n  private static final Expr f001125 = Expr.makePi(\"_\", f001124, f000085);\n  private static final Expr f001126 = Expr.makeLambda(\"m\", f000019, f001125);\n  private static final Expr f001127 = Expr.makeBuiltIn(\"Natural/build\");\n  private static final Expr f001128 = Expr.makeApplication(f000010, new Expr[] {f000221});\n  private static final Expr f001129 = Expr.makeNonEmptyListLiteral(new Expr[] {f000844});\n  private static final Expr f001130 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001129, f000248);\n  private static final Expr f001131 = Expr.makeLambda(\"as\", f001128, f001130);\n  private static final Expr f001132 = Expr.makeLambda(\"x\", f000883, f001131);\n  private static final Expr f001133 = Expr.makeEmptyListLiteral(f001128);\n  private static final Expr f001134 =\n      Expr.makeApplication(f000000, new Expr[] {f000883, f000892, f001128, f001132, f001133});\n  private static final Expr f001135 = Expr.makeLambda(\"n\", f000221, f001134);\n  private static final Expr f001136 = Expr.makeApplication(f000089, new Expr[] {f000029, f000070});\n  private static final Expr f001137 = Expr.makeApplication(f000074, new Expr[] {f001136});\n  private static final Expr f001138 = Expr.makeApplication(f000089, new Expr[] {f000070, f000029});\n  private static final Expr f001139 = Expr.makeApplication(f000074, new Expr[] {f001138});\n  private static final Expr f001140 = Expr.makeOperatorApplication(Operator.AND, f001137, f001139);\n  private static final Expr f001141 = Expr.makeLambda(\"b\", f000221, f001140);\n  private static final Expr f001142 = Expr.makeLambda(\"a\", f000221, f001141);\n  private static final Expr f001143 = Expr.makeBuiltIn(\"Natural/even\");\n  private static final Expr f001144 = Expr.makeApplication(f000089, new Expr[] {f000023, f000022});\n  private static final Expr f001145 = Expr.makeApplication(f000074, new Expr[] {f001144});\n  private static final Expr f001146 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f001145, f000014);\n  private static final Expr f001147 = Expr.makeLambda(\"y\", f000221, f001146);\n  private static final Expr f001148 = Expr.makeLambda(\"x\", f000221, f001147);\n  private static final Expr f001149 = Expr.makeApplication(f000089, new Expr[] {f000022, f000023});\n  private static final Expr f001150 = Expr.makeApplication(f000074, new Expr[] {f001149});\n  private static final Expr f001151 = Expr.makeLambda(\"y\", f000221, f001150);\n  private static final Expr f001152 = Expr.makeLambda(\"x\", f000221, f001151);\n  private static final Expr f001153 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f001150, f000014);\n  private static final Expr f001154 = Expr.makeLambda(\"y\", f000221, f001153);\n  private static final Expr f001155 = Expr.makeLambda(\"x\", f000221, f001154);\n  private static final Expr f001156 = Expr.makeLambda(\"y\", f000221, f001145);\n  private static final Expr f001157 = Expr.makeLambda(\"x\", f000221, f001156);\n  private static final Expr f001158 = Expr.makeIf(f001137, f000029, f000070);\n  private static final Expr f001159 = Expr.makeLambda(\"b\", f000221, f001158);\n  private static final Expr f001160 = Expr.makeLambda(\"a\", f000221, f001159);\n  private static final Expr f001161 =\n      Expr.makeApplication(f000000, new Expr[] {f000221, f000002, f000221, f001160, f000022});\n  private static final Expr f001162 = Expr.makeApplication(f000218, new Expr[] {f001161});\n  private static final Expr f001163 = Expr.makeLambda(\"x\", f000221, f001162);\n  private static final Expr f001164 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000222),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001163)\n          });\n  private static final Expr f001165 = Expr.makeApplication(f000903, new Expr[] {f000221, f000002});\n  private static final Expr f001166 = Expr.makeMerge(f001164, f001165, null);\n  private static final Expr f001167 = Expr.makeLambda(\"xs\", f001128, f001166);\n  private static final Expr f001168 = Expr.makeApplication(f000074, new Expr[] {f000022});\n  private static final Expr f001169 = Expr.makeIf(f001137, f000070, f000029);\n  private static final Expr f001170 = Expr.makeLambda(\"b\", f000221, f001169);\n  private static final Expr f001171 = Expr.makeLambda(\"a\", f000221, f001170);\n  private static final Expr f001172 =\n      Expr.makeApplication(f000000, new Expr[] {f000221, f000002, f000221, f001171, f000022});\n  private static final Expr f001173 = Expr.makeIf(f001168, f000022, f001172);\n  private static final Expr f001174 = Expr.makeApplication(f000218, new Expr[] {f001173});\n  private static final Expr f001175 = Expr.makeLambda(\"x\", f000221, f001174);\n  private static final Expr f001176 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000222),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001175)\n          });\n  private static final Expr f001177 = Expr.makeMerge(f001176, f001165, null);\n  private static final Expr f001178 = Expr.makeLambda(\"xs\", f001128, f001177);\n  private static final Expr f001179 = Expr.makeBuiltIn(\"Natural/odd\");\n  private static final Expr f001180 =\n      Expr.makeOperatorApplication(Operator.TIMES, f000003, f000004);\n  private static final Expr f001181 = Expr.makeLambda(\"r\", f000221, f001180);\n  private static final Expr f001182 = Expr.makeLambda(\"l\", f000221, f001181);\n  private static final Expr f001183 = Expr.makeNaturalLiteral(new BigInteger(\"1\"));\n  private static final Expr f001184 =\n      Expr.makeApplication(f000000, new Expr[] {f000221, f000002, f000221, f001182, f001183});\n  private static final Expr f001185 = Expr.makeLambda(\"xs\", f001128, f001184);\n  private static final Expr f001186 = Expr.makeApplication(f000921, new Expr[] {f000221, f000002});\n  private static final Expr f001187 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"rest\", f001128),\n            new SimpleImmutableEntry<String, Expr>(\"sorted\", f001128)\n          });\n  private static final Expr f001188 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"false\", f001133),\n            new SimpleImmutableEntry<String, Expr>(\"true\", f001133)\n          });\n  private static final Expr f001189 = Expr.makeFieldAccess(f000022, \"rest\");\n  private static final Expr f001190 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"false\", f001128),\n            new SimpleImmutableEntry<String, Expr>(\"true\", f001128)\n          });\n  private static final Expr f001191 = Expr.makeApplication(f000089, new Expr[] {f000085, f000022});\n  private static final Expr f001192 = Expr.makeApplication(f000074, new Expr[] {f001191});\n  private static final Expr f001193 = Expr.makeIf(f001192, f000941, f000943);\n  private static final Expr f001194 = Expr.makeLambda(\"p\", f001190, f001193);\n  private static final Expr f001195 = Expr.makeLambda(\"x\", f000221, f001194);\n  private static final Expr f001196 =\n      Expr.makeApplication(f000000, new Expr[] {f000221, f001189, f001190, f001195, f001188});\n  private static final Expr f001197 = Expr.makeLambda(\"m\", f000221, f001196);\n  private static final Expr f001198 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001188),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001197)\n          });\n  private static final Expr f001199 = Expr.makeFieldAccess(f000419, \"rest\");\n  private static final Expr f001200 =\n      Expr.makeApplication(f000000, new Expr[] {f000221, f001199, f000221, f001171, f000022});\n  private static final Expr f001201 = Expr.makeIf(f001168, f000022, f001200);\n  private static final Expr f001202 = Expr.makeApplication(f000218, new Expr[] {f001201});\n  private static final Expr f001203 = Expr.makeLambda(\"x\", f000221, f001202);\n  private static final Expr f001204 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000222),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001203)\n          });\n  private static final Expr f001205 = Expr.makeApplication(f000903, new Expr[] {f000221, f001189});\n  private static final Expr f001206 = Expr.makeMerge(f001204, f001205, null);\n  private static final Expr f001207 = Expr.makeMerge(f001198, f001206, null);\n  private static final Expr f001208 = Expr.makeFieldAccess(f001207, \"false\");\n  private static final Expr f001209 = Expr.makeFieldAccess(f000022, \"sorted\");\n  private static final Expr f001210 = Expr.makeFieldAccess(f001207, \"true\");\n  private static final Expr f001211 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001209, f001210);\n  private static final Expr f001212 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"rest\", f001208),\n            new SimpleImmutableEntry<String, Expr>(\"sorted\", f001211)\n          });\n  private static final Expr f001213 = Expr.makeLambda(\"x\", f001187, f001212);\n  private static final Expr f001214 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"rest\", f000002),\n            new SimpleImmutableEntry<String, Expr>(\"sorted\", f001133)\n          });\n  private static final Expr f001215 =\n      Expr.makeApplication(f000884, new Expr[] {f001186, f001187, f001213, f001214});\n  private static final Expr f001216 = Expr.makeFieldAccess(f001215, \"sorted\");\n  private static final Expr f001217 = Expr.makeLambda(\"xs\", f001128, f001216);\n  private static final Expr f001218 = Expr.makeOperatorApplication(Operator.PLUS, f000003, f000004);\n  private static final Expr f001219 = Expr.makeLambda(\"r\", f000221, f001218);\n  private static final Expr f001220 = Expr.makeLambda(\"l\", f000221, f001219);\n  private static final Expr f001221 =\n      Expr.makeApplication(f000000, new Expr[] {f000221, f000002, f000221, f001220, f000984});\n  private static final Expr f001222 = Expr.makeLambda(\"xs\", f001128, f001221);\n  private static final Expr f001223 = Expr.makeApplication(f000094, new Expr[] {f000076});\n  private static final Expr f001224 = Expr.makeApplication(f000217, new Expr[] {f001223});\n  private static final Expr f001225 = Expr.makeLambda(\"n\", f000221, f001224);\n  private static final Expr f001226 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"build\", f001127),\n            new SimpleImmutableEntry<String, Expr>(\"enumerate\", f001135),\n            new SimpleImmutableEntry<String, Expr>(\"equal\", f001142),\n            new SimpleImmutableEntry<String, Expr>(\"even\", f001143),\n            new SimpleImmutableEntry<String, Expr>(\"fold\", f000884),\n            new SimpleImmutableEntry<String, Expr>(\"greaterThan\", f001148),\n            new SimpleImmutableEntry<String, Expr>(\"greaterThanEqual\", f001152),\n            new SimpleImmutableEntry<String, Expr>(\"isZero\", f000074),\n            new SimpleImmutableEntry<String, Expr>(\"lessThan\", f001155),\n            new SimpleImmutableEntry<String, Expr>(\"lessThanEqual\", f001157),\n            new SimpleImmutableEntry<String, Expr>(\"listMax\", f001167),\n            new SimpleImmutableEntry<String, Expr>(\"listMin\", f001178),\n            new SimpleImmutableEntry<String, Expr>(\"max\", f001160),\n            new SimpleImmutableEntry<String, Expr>(\"min\", f001171),\n            new SimpleImmutableEntry<String, Expr>(\"odd\", f001179),\n            new SimpleImmutableEntry<String, Expr>(\"product\", f001185),\n            new SimpleImmutableEntry<String, Expr>(\"show\", f000516),\n            new SimpleImmutableEntry<String, Expr>(\"sort\", f001217),\n            new SimpleImmutableEntry<String, Expr>(\"subtract\", f000089),\n            new SimpleImmutableEntry<String, Expr>(\"sum\", f001222),\n            new SimpleImmutableEntry<String, Expr>(\"toDouble\", f001225),\n            new SimpleImmutableEntry<String, Expr>(\"toInteger\", f000094)\n          });\n  private static final Expr f001227 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000070),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000795)\n          });\n  private static final Expr f001228 = Expr.makeLambda(\"a\", f000019, f001227);\n  private static final Expr f001229 = Expr.makeFieldAccess(f000002, \"head\");\n  private static final Expr f001230 = Expr.makeNonEmptyListLiteral(new Expr[] {f001229});\n  private static final Expr f001231 = Expr.makeFieldAccess(f000002, \"tail\");\n  private static final Expr f001232 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001230, f001231);\n  private static final Expr f001233 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f001232, f000001, f000793, f000008});\n  private static final Expr f001234 = Expr.makeLambda(\"xs\", f001227, f001233);\n  private static final Expr f001235 = Expr.makeLambda(\"f\", f000797, f001234);\n  private static final Expr f001236 = Expr.makeLambda(\"a\", f000019, f001235);\n  private static final Expr f001237 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f001232, f000001, f000802, f000014});\n  private static final Expr f001238 = Expr.makeLambda(\"xs\", f001227, f001237);\n  private static final Expr f001239 = Expr.makeLambda(\"f\", f000797, f001238);\n  private static final Expr f001240 = Expr.makeLambda(\"a\", f000019, f001239);\n  private static final Expr f001241 = Expr.makeFieldAccess(f000808, \"head\");\n  private static final Expr f001242 = Expr.makeFieldAccess(f001241, \"head\");\n  private static final Expr f001243 = Expr.makeFieldAccess(f001241, \"tail\");\n  private static final Expr f001244 = Expr.makeFieldAccess(f000808, \"tail\");\n  private static final Expr f001245 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000473, f000795, f000812});\n  private static final Expr f001246 = Expr.makeLambda(\"x\", f001227, f001245);\n  private static final Expr f001247 =\n      Expr.makeApplication(f000000, new Expr[] {f001227, f001244, f000795, f001246, f000817});\n  private static final Expr f001248 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001243, f001247);\n  private static final Expr f001249 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001242),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001248)\n          });\n  private static final Expr f001250 = Expr.makeApplication(f000010, new Expr[] {f001227});\n  private static final Expr f001251 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001227),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001250)\n          });\n  private static final Expr f001252 = Expr.makeLambda(\"xss\", f001251, f001249);\n  private static final Expr f001253 = Expr.makeLambda(\"a\", f000019, f001252);\n  private static final Expr f001254 = Expr.makeApplication(f000013, new Expr[] {f001229});\n  private static final Expr f001255 = Expr.makeFieldAccess(f001254, \"head\");\n  private static final Expr f001256 = Expr.makeFieldAccess(f001254, \"tail\");\n  private static final Expr f001257 = Expr.makeFieldAccess(f000057, \"head\");\n  private static final Expr f001258 = Expr.makeNonEmptyListLiteral(new Expr[] {f001257});\n  private static final Expr f001259 = Expr.makeFieldAccess(f000057, \"tail\");\n  private static final Expr f001260 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001258, f001259);\n  private static final Expr f001261 =\n      Expr.makeApplication(f000000, new Expr[] {f000029, f001260, f000822, f000824});\n  private static final Expr f001262 = Expr.makeLambda(\"x\", f000070, f001261);\n  private static final Expr f001263 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f001231, f000822, f001262, f000827});\n  private static final Expr f001264 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001256, f001263);\n  private static final Expr f001265 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001255),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001264)\n          });\n  private static final Expr f001266 = Expr.makeLambda(\"xs\", f001227, f001265);\n  private static final Expr f001267 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000029),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000822)\n          });\n  private static final Expr f001268 = Expr.makePi(\"_\", f000070, f001267);\n  private static final Expr f001269 = Expr.makeLambda(\"f\", f001268, f001266);\n  private static final Expr f001270 = Expr.makeLambda(\"b\", f000019, f001269);\n  private static final Expr f001271 = Expr.makeLambda(\"a\", f000019, f001270);\n  private static final Expr f001272 = Expr.makeLambda(\"xs\", f001227, f001229);\n  private static final Expr f001273 = Expr.makeLambda(\"a\", f000019, f001272);\n  private static final Expr f001274 = Expr.makeApplication(f000074, new Expr[] {f000076});\n  private static final Expr f001275 = Expr.makeApplication(f000218, new Expr[] {f001229});\n  private static final Expr f001276 = Expr.makeApplication(f000842, new Expr[] {f000070, f001231});\n  private static final Expr f001277 = Expr.makeApplication(f000089, new Expr[] {f001183, f000076});\n  private static final Expr f001278 = Expr.makeApplication(f000089, new Expr[] {f000844, f001277});\n  private static final Expr f001279 = Expr.makeApplication(f000074, new Expr[] {f001278});\n  private static final Expr f001280 = Expr.makeIf(f001279, f000847, f000002);\n  private static final Expr f001281 = Expr.makeLambda(\"xs\", f000795, f001280);\n  private static final Expr f001282 = Expr.makeLambda(\"x\", f000841, f001281);\n  private static final Expr f001283 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f001276, f000795, f001282, f000817});\n  private static final Expr f001284 = Expr.makeApplication(f000903, new Expr[] {f000070, f001283});\n  private static final Expr f001285 = Expr.makeIf(f001274, f001275, f001284);\n  private static final Expr f001286 = Expr.makeLambda(\"xs\", f001227, f001285);\n  private static final Expr f001287 = Expr.makeLambda(\"a\", f000019, f001286);\n  private static final Expr f001288 = Expr.makeLambda(\"n\", f000221, f001287);\n  private static final Expr f001289 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"index\", f000984),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f001229)\n          });\n  private static final Expr f001290 = Expr.makeOperatorApplication(Operator.PLUS, f000844, f001183);\n  private static final Expr f001291 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"index\", f001290),\n            new SimpleImmutableEntry<String, Expr>(\"value\", f000310)\n          });\n  private static final Expr f001292 = Expr.makeNonEmptyListLiteral(new Expr[] {f001291});\n  private static final Expr f001293 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001292, f000248);\n  private static final Expr f001294 = Expr.makeLambda(\"as\", f000958, f001293);\n  private static final Expr f001295 = Expr.makeLambda(\"x\", f000841, f001294);\n  private static final Expr f001296 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f001276, f000958, f001295, f000985});\n  private static final Expr f001297 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001289),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001296)\n          });\n  private static final Expr f001298 = Expr.makeLambda(\"xs\", f001227, f001297);\n  private static final Expr f001299 = Expr.makeLambda(\"a\", f000019, f001298);\n  private static final Expr f001300 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001229),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000071)\n          });\n  private static final Expr f001301 = Expr.makeApplication(f000920, new Expr[] {f000070, f001231});\n  private static final Expr f001302 = Expr.makeMerge(f001300, f001301, null);\n  private static final Expr f001303 = Expr.makeLambda(\"xs\", f001227, f001302);\n  private static final Expr f001304 = Expr.makeLambda(\"a\", f000019, f001303);\n  private static final Expr f001305 = Expr.makeApplication(f000921, new Expr[] {f000070, f001231});\n  private static final Expr f001306 = Expr.makeOperatorApplication(Operator.PLUS, f001305, f001183);\n  private static final Expr f001307 = Expr.makeLambda(\"xs\", f001227, f001306);\n  private static final Expr f001308 = Expr.makeLambda(\"a\", f000019, f001307);\n  private static final Expr f001309 = Expr.makeIdentifier(\"head\", 0);\n  private static final Expr f001310 = Expr.makeIdentifier(\"tail\", 0);\n  private static final Expr f001311 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001309),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001310)\n          });\n  private static final Expr f001312 = Expr.makeLambda(\"tail\", f000795, f001311);\n  private static final Expr f001313 = Expr.makeLambda(\"head\", f000070, f001312);\n  private static final Expr f001314 = Expr.makeLambda(\"a\", f000019, f001313);\n  private static final Expr f001315 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f001231, f000822, f000925, f000827});\n  private static final Expr f001316 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001254),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001315)\n          });\n  private static final Expr f001317 = Expr.makeLambda(\"xs\", f001227, f001316);\n  private static final Expr f001318 = Expr.makeLambda(\"f\", f000928, f001317);\n  private static final Expr f001319 = Expr.makeLambda(\"b\", f000019, f001318);\n  private static final Expr f001320 = Expr.makeLambda(\"a\", f000019, f001319);\n  private static final Expr f001321 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001229),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000817)\n          });\n  private static final Expr f001322 = Expr.makeApplication(f000487, new Expr[] {f000070, f001231});\n  private static final Expr f001323 = Expr.makeApplication(f000842, new Expr[] {f000070, f001322});\n  private static final Expr f001324 = Expr.makeApplication(f000089, new Expr[] {f000844, f001183});\n  private static final Expr f001325 = Expr.makeApplication(f000074, new Expr[] {f001324});\n  private static final Expr f001326 = Expr.makeIf(f001325, f000847, f000002);\n  private static final Expr f001327 = Expr.makeLambda(\"xs\", f000795, f001326);\n  private static final Expr f001328 = Expr.makeLambda(\"x\", f000841, f001327);\n  private static final Expr f001329 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f001323, f000795, f001328, f000817});\n  private static final Expr f001330 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001329, f001230);\n  private static final Expr f001331 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000023),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001330)\n          });\n  private static final Expr f001332 = Expr.makeLambda(\"y\", f000070, f001331);\n  private static final Expr f001333 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001321),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001332)\n          });\n  private static final Expr f001334 = Expr.makeApplication(f000903, new Expr[] {f000070, f001322});\n  private static final Expr f001335 = Expr.makeMerge(f001333, f001334, null);\n  private static final Expr f001336 = Expr.makeLambda(\"xs\", f001227, f001335);\n  private static final Expr f001337 = Expr.makeLambda(\"a\", f000019, f001336);\n  private static final Expr f001338 = Expr.makeFieldAccess(f000959, \"head\");\n  private static final Expr f001339 = Expr.makeFieldAccess(f001338, \"head\");\n  private static final Expr f001340 = Expr.makeFieldAccess(f001338, \"tail\");\n  private static final Expr f001341 = Expr.makeNonEmptyListLiteral(new Expr[] {f001340});\n  private static final Expr f001342 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000841),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000958)\n          });\n  private static final Expr f001343 = Expr.makeFieldAccess(f000959, \"tail\");\n  private static final Expr f001344 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f000473, f000958, f001295, f000985});\n  private static final Expr f001345 = Expr.makeNonEmptyListLiteral(new Expr[] {f001344});\n  private static final Expr f001346 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001345, f000248);\n  private static final Expr f001347 = Expr.makeLambda(\"as\", f000991, f001346);\n  private static final Expr f001348 = Expr.makeLambda(\"x\", f001342, f001347);\n  private static final Expr f001349 = Expr.makeEmptyListLiteral(f000991);\n  private static final Expr f001350 =\n      Expr.makeApplication(f000000, new Expr[] {f001342, f001343, f000991, f001348, f001349});\n  private static final Expr f001351 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001341, f001350);\n  private static final Expr f001352 =\n      Expr.makeApplication(f000000, new Expr[] {f000958, f001351, f000961, f000983, f000987});\n  private static final Expr f001353 = Expr.makeFieldAccess(f001352, \"diff\");\n  private static final Expr f001354 = Expr.makeApplication(f001353, new Expr[] {f000984});\n  private static final Expr f001355 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001339),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001354)\n          });\n  private static final Expr f001356 = Expr.makeApplication(f000010, new Expr[] {f001342});\n  private static final Expr f001357 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001342),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001356)\n          });\n  private static final Expr f001358 = Expr.makeLambda(\"kvss\", f001357, f001355);\n  private static final Expr f001359 = Expr.makeLambda(\"a\", f000019, f001358);\n  private static final Expr f001360 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f000022),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f000817)\n          });\n  private static final Expr f001361 = Expr.makeLambda(\"x\", f000070, f001360);\n  private static final Expr f001362 = Expr.makeLambda(\"a\", f000019, f001361);\n  private static final Expr f001363 = Expr.makeLambda(\"xs\", f001227, f001232);\n  private static final Expr f001364 = Expr.makeLambda(\"a\", f000019, f001363);\n  private static final Expr f001365 = Expr.makeFieldAccess(f001229, \"_1\");\n  private static final Expr f001366 =\n      Expr.makeApplication(f000000, new Expr[] {f001012, f001231, f000795, f001017, f000817});\n  private static final Expr f001367 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001365),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001366)\n          });\n  private static final Expr f001368 = Expr.makeFieldAccess(f001229, \"_2\");\n  private static final Expr f001369 =\n      Expr.makeApplication(f000000, new Expr[] {f001012, f001231, f000822, f001023, f000827});\n  private static final Expr f001370 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001368),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001369)\n          });\n  private static final Expr f001371 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"_1\", f001367),\n            new SimpleImmutableEntry<String, Expr>(\"_2\", f001370)\n          });\n  private static final Expr f001372 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001012),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001026)\n          });\n  private static final Expr f001373 = Expr.makeLambda(\"xs\", f001372, f001371);\n  private static final Expr f001374 = Expr.makeLambda(\"b\", f000019, f001373);\n  private static final Expr f001375 = Expr.makeLambda(\"a\", f000019, f001374);\n  private static final Expr f001376 = Expr.makeFieldAccess(f000813, \"head\");\n  private static final Expr f001377 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"_1\", f001229),\n            new SimpleImmutableEntry<String, Expr>(\"_2\", f001376)\n          });\n  private static final Expr f001378 = Expr.makeFieldAccess(f000813, \"tail\");\n  private static final Expr f001379 = Expr.makeApplication(f000842, new Expr[] {f000029, f001378});\n  private static final Expr f001380 =\n      Expr.makeApplication(f000000, new Expr[] {f001038, f001379, f000822, f001045, f000827});\n  private static final Expr f001381 = Expr.makeApplication(f000903, new Expr[] {f000029, f001380});\n  private static final Expr f001382 = Expr.makeMerge(f001037, f001381, null);\n  private static final Expr f001383 = Expr.makeLambda(\"rest\", f001026, f001382);\n  private static final Expr f001384 = Expr.makeLambda(\"ix\", f000841, f001383);\n  private static final Expr f001385 =\n      Expr.makeApplication(f000000, new Expr[] {f000841, f001276, f001026, f001384, f001051});\n  private static final Expr f001386 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001377),\n            new SimpleImmutableEntry<String, Expr>(\"tail\", f001385)\n          });\n  private static final Expr f001387 = Expr.makeLambda(\"ys\", f001267, f001386);\n  private static final Expr f001388 = Expr.makeLambda(\"b\", f000019, f001387);\n  private static final Expr f001389 = Expr.makeLambda(\"xs\", f001227, f001388);\n  private static final Expr f001390 = Expr.makeLambda(\"a\", f000019, f001389);\n  private static final Expr f001391 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Type\", f001228),\n            new SimpleImmutableEntry<String, Expr>(\"all\", f001236),\n            new SimpleImmutableEntry<String, Expr>(\"any\", f001240),\n            new SimpleImmutableEntry<String, Expr>(\"concat\", f001253),\n            new SimpleImmutableEntry<String, Expr>(\"concatMap\", f001271),\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001273),\n            new SimpleImmutableEntry<String, Expr>(\"index\", f001288),\n            new SimpleImmutableEntry<String, Expr>(\"indexed\", f001299),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f001304),\n            new SimpleImmutableEntry<String, Expr>(\"length\", f001308),\n            new SimpleImmutableEntry<String, Expr>(\"make\", f001314),\n            new SimpleImmutableEntry<String, Expr>(\"map\", f001320),\n            new SimpleImmutableEntry<String, Expr>(\"reverse\", f001337),\n            new SimpleImmutableEntry<String, Expr>(\"shifted\", f001359),\n            new SimpleImmutableEntry<String, Expr>(\"singleton\", f001362),\n            new SimpleImmutableEntry<String, Expr>(\"toList\", f001364),\n            new SimpleImmutableEntry<String, Expr>(\"unzip\", f001375),\n            new SimpleImmutableEntry<String, Expr>(\"zip\", f001390)\n          });\n  private static final Expr f001392 =\n      Expr.makeOperatorApplication(Operator.NOT_EQUALS, f000085, f000076);\n  private static final Expr f001393 = Expr.makeLambda(\"n\", f000001, f001392);\n  private static final Expr f001394 = Expr.makeLambda(\"m\", f000001, f001393);\n  private static final Expr f001395 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f000085, f000076);\n  private static final Expr f001396 = Expr.makeIdentifier(\"type\", 0);\n  private static final Expr f001397 = Expr.makeApplication(f000010, new Expr[] {f001396});\n  private static final Expr f001398 = Expr.makeLambda(\"n\", f001397, f001395);\n  private static final Expr f001399 = Expr.makeLambda(\"m\", f001397, f001398);\n  private static final Expr f001400 = Expr.makeLambda(\"type\", f000019, f001399);\n  private static final Expr f001401 = Expr.makeOperatorApplication(Operator.AND, f000085, f000076);\n  private static final Expr f001402 = Expr.makeLambda(\"n\", f000001, f001401);\n  private static final Expr f001403 = Expr.makeLambda(\"m\", f000001, f001402);\n  private static final Expr f001404 =\n      Expr.makeOperatorApplication(Operator.TIMES, f000085, f000076);\n  private static final Expr f001405 = Expr.makeLambda(\"n\", f000221, f001404);\n  private static final Expr f001406 = Expr.makeLambda(\"m\", f000221, f001405);\n  private static final Expr f001407 = Expr.makeOperatorApplication(Operator.PLUS, f000085, f000076);\n  private static final Expr f001408 = Expr.makeLambda(\"n\", f000221, f001407);\n  private static final Expr f001409 = Expr.makeLambda(\"m\", f000221, f001408);\n  private static final Expr f001410 =\n      Expr.makeTextLiteral(new String[] {\"\", \"\", \"\"}, new Expr[] {f000085, f000076});\n  private static final Expr f001411 = Expr.makeLambda(\"n\", f000226, f001410);\n  private static final Expr f001412 = Expr.makeLambda(\"m\", f000226, f001411);\n  private static final Expr f001413 =\n      Expr.makeOperatorApplication(Operator.EQUALS, f000085, f000076);\n  private static final Expr f001414 = Expr.makeLambda(\"n\", f000001, f001413);\n  private static final Expr f001415 = Expr.makeLambda(\"m\", f000001, f001414);\n  private static final Expr f001416 = Expr.makeOperatorApplication(Operator.OR, f000085, f000076);\n  private static final Expr f001417 = Expr.makeLambda(\"n\", f000001, f001416);\n  private static final Expr f001418 = Expr.makeLambda(\"m\", f000001, f001417);\n  private static final Expr f001419 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"!=\", f001394),\n            new SimpleImmutableEntry<String, Expr>(\"#\", f001400),\n            new SimpleImmutableEntry<String, Expr>(\"&&\", f001403),\n            new SimpleImmutableEntry<String, Expr>(\"*\", f001406),\n            new SimpleImmutableEntry<String, Expr>(\"+\", f001409),\n            new SimpleImmutableEntry<String, Expr>(\"++\", f001412),\n            new SimpleImmutableEntry<String, Expr>(\"==\", f001415),\n            new SimpleImmutableEntry<String, Expr>(\"||\", f001418)\n          });\n  private static final Expr f001420 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000008),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000013)\n          });\n  private static final Expr f001421 = Expr.makeMerge(f001420, f000002, null);\n  private static final Expr f001422 = Expr.makeLambda(\"xs\", f001002, f001421);\n  private static final Expr f001423 = Expr.makeLambda(\"f\", f000797, f001422);\n  private static final Expr f001424 = Expr.makeLambda(\"a\", f000019, f001423);\n  private static final Expr f001425 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000014),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000013)\n          });\n  private static final Expr f001426 = Expr.makeMerge(f001425, f000002, null);\n  private static final Expr f001427 = Expr.makeLambda(\"xs\", f001002, f001426);\n  private static final Expr f001428 = Expr.makeLambda(\"f\", f000797, f001427);\n  private static final Expr f001429 = Expr.makeLambda(\"a\", f000019, f001428);\n  private static final Expr f001430 = Expr.makeIdentifier(\"build\", 0);\n  private static final Expr f001431 = Expr.makeApplication(f000218, new Expr[] {f000022});\n  private static final Expr f001432 = Expr.makeLambda(\"x\", f000070, f001431);\n  private static final Expr f001433 = Expr.makeApplication(f000220, new Expr[] {f000070});\n  private static final Expr f001434 =\n      Expr.makeApplication(f001430, new Expr[] {f001002, f001432, f001433});\n  private static final Expr f001435 = Expr.makeIdentifier(\"optional\", 0);\n  private static final Expr f001436 = Expr.makePi(\"none\", f001435, f001435);\n  private static final Expr f001437 = Expr.makePi(\"_\", f000070, f001435);\n  private static final Expr f001438 = Expr.makePi(\"some\", f001437, f001436);\n  private static final Expr f001439 = Expr.makePi(\"optional\", f000019, f001438);\n  private static final Expr f001440 = Expr.makeLambda(\"build\", f001439, f001434);\n  private static final Expr f001441 = Expr.makeLambda(\"a\", f000019, f001440);\n  private static final Expr f001442 = Expr.makeLambda(\"y\", f001002, f000023);\n  private static final Expr f001443 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001433),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001442)\n          });\n  private static final Expr f001444 = Expr.makeMerge(f001443, f000022, null);\n  private static final Expr f001445 = Expr.makeApplication(f000396, new Expr[] {f001002});\n  private static final Expr f001446 = Expr.makeLambda(\"x\", f001445, f001444);\n  private static final Expr f001447 = Expr.makeLambda(\"a\", f000019, f001446);\n  private static final Expr f001448 = Expr.makeApplication(f000220, new Expr[] {f000029});\n  private static final Expr f001449 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001448),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000013)\n          });\n  private static final Expr f001450 = Expr.makeMerge(f001449, f000836, null);\n  private static final Expr f001451 = Expr.makeLambda(\"o\", f001002, f001450);\n  private static final Expr f001452 = Expr.makeApplication(f000396, new Expr[] {f000029});\n  private static final Expr f001453 = Expr.makePi(\"_\", f000070, f001452);\n  private static final Expr f001454 = Expr.makeLambda(\"f\", f001453, f001451);\n  private static final Expr f001455 = Expr.makeLambda(\"b\", f000019, f001454);\n  private static final Expr f001456 = Expr.makeLambda(\"a\", f000019, f001455);\n  private static final Expr f001457 = Expr.makeIdentifier(\"default\", 0);\n  private static final Expr f001458 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001457),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000071)\n          });\n  private static final Expr f001459 = Expr.makeMerge(f001458, f000836, null);\n  private static final Expr f001460 = Expr.makeLambda(\"o\", f001002, f001459);\n  private static final Expr f001461 = Expr.makeLambda(\"default\", f000070, f001460);\n  private static final Expr f001462 = Expr.makeLambda(\"a\", f000019, f001461);\n  private static final Expr f001463 = Expr.makeIf(f000057, f001431, f001433);\n  private static final Expr f001464 = Expr.makeLambda(\"x\", f000070, f001463);\n  private static final Expr f001465 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001433),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001464)\n          });\n  private static final Expr f001466 = Expr.makeMerge(f001465, f000002, null);\n  private static final Expr f001467 = Expr.makeLambda(\"xs\", f001002, f001466);\n  private static final Expr f001468 = Expr.makeLambda(\"f\", f000797, f001467);\n  private static final Expr f001469 = Expr.makeLambda(\"a\", f000019, f001468);\n  private static final Expr f001470 = Expr.makeIdentifier(\"none\", 0);\n  private static final Expr f001471 = Expr.makeIdentifier(\"some\", 0);\n  private static final Expr f001472 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001470),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001471)\n          });\n  private static final Expr f001473 = Expr.makeMerge(f001472, f000836, null);\n  private static final Expr f001474 = Expr.makeLambda(\"none\", f001435, f001473);\n  private static final Expr f001475 = Expr.makeLambda(\"some\", f001437, f001474);\n  private static final Expr f001476 = Expr.makeLambda(\"optional\", f000019, f001475);\n  private static final Expr f001477 = Expr.makeLambda(\"o\", f001002, f001476);\n  private static final Expr f001478 = Expr.makeLambda(\"a\", f000019, f001477);\n  private static final Expr f001479 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000004),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001432)\n          });\n  private static final Expr f001480 = Expr.makeMerge(f001479, f000003, null);\n  private static final Expr f001481 = Expr.makeLambda(\"r\", f001002, f001480);\n  private static final Expr f001482 = Expr.makeLambda(\"l\", f001002, f001481);\n  private static final Expr f001483 =\n      Expr.makeApplication(f000000, new Expr[] {f001002, f000002, f001002, f001482, f001433});\n  private static final Expr f001484 = Expr.makeLambda(\"xs\", f001009, f001483);\n  private static final Expr f001485 = Expr.makeLambda(\"a\", f000019, f001484);\n  private static final Expr f001486 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000003),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001432)\n          });\n  private static final Expr f001487 = Expr.makeMerge(f001486, f000004, null);\n  private static final Expr f001488 = Expr.makeLambda(\"r\", f001002, f001487);\n  private static final Expr f001489 = Expr.makeLambda(\"l\", f001002, f001488);\n  private static final Expr f001490 =\n      Expr.makeApplication(f000000, new Expr[] {f001002, f000002, f001002, f001489, f001433});\n  private static final Expr f001491 = Expr.makeLambda(\"xs\", f001009, f001490);\n  private static final Expr f001492 = Expr.makeLambda(\"a\", f000019, f001491);\n  private static final Expr f001493 = Expr.makeLambda(\"_\", f000070, f001183);\n  private static final Expr f001494 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000984),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001493)\n          });\n  private static final Expr f001495 = Expr.makeMerge(f001494, f000002, null);\n  private static final Expr f001496 = Expr.makeLambda(\"xs\", f001002, f001495);\n  private static final Expr f001497 = Expr.makeLambda(\"a\", f000019, f001496);\n  private static final Expr f001498 = Expr.makeApplication(f000218, new Expr[] {f000057});\n  private static final Expr f001499 = Expr.makeLambda(\"x\", f000070, f001498);\n  private static final Expr f001500 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001448),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001499)\n          });\n  private static final Expr f001501 = Expr.makeMerge(f001500, f000836, null);\n  private static final Expr f001502 = Expr.makeLambda(\"o\", f001002, f001501);\n  private static final Expr f001503 = Expr.makeLambda(\"f\", f000928, f001502);\n  private static final Expr f001504 = Expr.makeLambda(\"b\", f000019, f001503);\n  private static final Expr f001505 = Expr.makeLambda(\"a\", f000019, f001504);\n  private static final Expr f001506 = Expr.makeLambda(\"_\", f000070, f000014);\n  private static final Expr f001507 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000008),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001506)\n          });\n  private static final Expr f001508 = Expr.makeMerge(f001507, f000002, null);\n  private static final Expr f001509 = Expr.makeLambda(\"xs\", f001002, f001508);\n  private static final Expr f001510 = Expr.makeLambda(\"a\", f000019, f001509);\n  private static final Expr f001511 = Expr.makeMerge(f001004, f000836, null);\n  private static final Expr f001512 = Expr.makeLambda(\"o\", f001002, f001511);\n  private static final Expr f001513 = Expr.makeLambda(\"a\", f000019, f001512);\n  private static final Expr f001514 = Expr.makeApplication(f000218, new Expr[] {f001013});\n  private static final Expr f001515 = Expr.makeLambda(\"x\", f001012, f001514);\n  private static final Expr f001516 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001433),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001515)\n          });\n  private static final Expr f001517 = Expr.makeMerge(f001516, f000002, null);\n  private static final Expr f001518 = Expr.makeApplication(f000218, new Expr[] {f001019});\n  private static final Expr f001519 = Expr.makeLambda(\"x\", f001012, f001518);\n  private static final Expr f001520 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f001448),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001519)\n          });\n  private static final Expr f001521 = Expr.makeMerge(f001520, f000002, null);\n  private static final Expr f001522 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"_1\", f001517),\n            new SimpleImmutableEntry<String, Expr>(\"_2\", f001521)\n          });\n  private static final Expr f001523 = Expr.makeApplication(f000396, new Expr[] {f001012});\n  private static final Expr f001524 = Expr.makeLambda(\"xs\", f001523, f001522);\n  private static final Expr f001525 = Expr.makeLambda(\"b\", f000019, f001524);\n  private static final Expr f001526 = Expr.makeLambda(\"a\", f000019, f001525);\n  private static final Expr f001527 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"all\", f001424),\n            new SimpleImmutableEntry<String, Expr>(\"any\", f001429),\n            new SimpleImmutableEntry<String, Expr>(\"build\", f001441),\n            new SimpleImmutableEntry<String, Expr>(\"concat\", f001447),\n            new SimpleImmutableEntry<String, Expr>(\"concatMap\", f001456),\n            new SimpleImmutableEntry<String, Expr>(\"default\", f001462),\n            new SimpleImmutableEntry<String, Expr>(\"filter\", f001469),\n            new SimpleImmutableEntry<String, Expr>(\"fold\", f001478),\n            new SimpleImmutableEntry<String, Expr>(\"head\", f001485),\n            new SimpleImmutableEntry<String, Expr>(\"last\", f001492),\n            new SimpleImmutableEntry<String, Expr>(\"length\", f001497),\n            new SimpleImmutableEntry<String, Expr>(\"map\", f001505),\n            new SimpleImmutableEntry<String, Expr>(\"null\", f001510),\n            new SimpleImmutableEntry<String, Expr>(\"toList\", f001513),\n            new SimpleImmutableEntry<String, Expr>(\"unzip\", f001526)\n          });\n  private static final Expr f001528 =\n      Expr.makeTextLiteral(new String[] {\"\", \"\", \"\"}, new Expr[] {f000022, f000023});\n  private static final Expr f001529 = Expr.makeLambda(\"y\", f000226, f001528);\n  private static final Expr f001530 = Expr.makeLambda(\"x\", f000226, f001529);\n  private static final Expr f001531 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f000002, f000226, f001530, f000647});\n  private static final Expr f001532 = Expr.makeLambda(\"xs\", f000357, f001531);\n  private static final Expr f001533 =\n      Expr.makeTextLiteral(new String[] {\"\", \"\", \"\"}, new Expr[] {f000057, f000023});\n  private static final Expr f001534 = Expr.makeLambda(\"y\", f000226, f001533);\n  private static final Expr f001535 = Expr.makeLambda(\"x\", f000070, f001534);\n  private static final Expr f001536 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f000002, f000226, f001535, f000647});\n  private static final Expr f001537 = Expr.makeLambda(\"xs\", f000795, f001536);\n  private static final Expr f001538 = Expr.makePi(\"_\", f000070, f000226);\n  private static final Expr f001539 = Expr.makeLambda(\"f\", f001538, f001537);\n  private static final Expr f001540 = Expr.makeLambda(\"a\", f000019, f001539);\n  private static final Expr f001541 = Expr.makeIdentifier(\"elements\", 0);\n  private static final Expr f001542 = Expr.makeApplication(f000655, new Expr[] {f000057});\n  private static final Expr f001543 = Expr.makeIdentifier(\"separator\", 0);\n  private static final Expr f001544 =\n      Expr.makeTextLiteral(new String[] {\"\", \"\", \"\", \"\"}, new Expr[] {f000057, f001543, f000651});\n  private static final Expr f001545 = Expr.makeApplication(f000655, new Expr[] {f001544});\n  private static final Expr f001546 = Expr.makeLambda(\"result\", f000226, f001545);\n  private static final Expr f001547 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Empty\", f001542),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f001546)\n          });\n  private static final Expr f001548 = Expr.makeMerge(f001547, f000662, null);\n  private static final Expr f001549 = Expr.makeLambda(\"status\", f000654, f001548);\n  private static final Expr f001550 = Expr.makeLambda(\"x\", f000070, f001549);\n  private static final Expr f001551 =\n      Expr.makeApplication(f000000, new Expr[] {f000070, f001541, f000654, f001550, f000666});\n  private static final Expr f001552 = Expr.makeMerge(f000653, f001551, null);\n  private static final Expr f001553 = Expr.makeLambda(\"elements\", f000795, f001552);\n  private static final Expr f001554 = Expr.makeLambda(\"f\", f001538, f001553);\n  private static final Expr f001555 = Expr.makeLambda(\"a\", f000019, f001554);\n  private static final Expr f001556 = Expr.makeLambda(\"separator\", f000226, f001555);\n  private static final Expr f001557 = Expr.makeIdentifier(\"element\", 0);\n  private static final Expr f001558 = Expr.makeApplication(f000655, new Expr[] {f001557});\n  private static final Expr f001559 =\n      Expr.makeTextLiteral(new String[] {\"\", \"\", \"\", \"\"}, new Expr[] {f001557, f001543, f000651});\n  private static final Expr f001560 = Expr.makeApplication(f000655, new Expr[] {f001559});\n  private static final Expr f001561 = Expr.makeLambda(\"result\", f000226, f001560);\n  private static final Expr f001562 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Empty\", f001558),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f001561)\n          });\n  private static final Expr f001563 = Expr.makeMerge(f001562, f000662, null);\n  private static final Expr f001564 = Expr.makeLambda(\"status\", f000654, f001563);\n  private static final Expr f001565 = Expr.makeLambda(\"element\", f000226, f001564);\n  private static final Expr f001566 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f001541, f000654, f001565, f000666});\n  private static final Expr f001567 = Expr.makeMerge(f000653, f001566, null);\n  private static final Expr f001568 = Expr.makeLambda(\"elements\", f000357, f001567);\n  private static final Expr f001569 = Expr.makeLambda(\"separator\", f000226, f001568);\n  private static final Expr f001570 = Expr.makeIdentifier(\"t\", 0);\n  private static final Expr f001571 = Expr.makeLambda(\"t\", f000226, f001570);\n  private static final Expr f001572 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000647),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f001571)\n          });\n  private static final Expr f001573 = Expr.makeMerge(f001572, f000836, null);\n  private static final Expr f001574 = Expr.makeApplication(f000396, new Expr[] {f000226});\n  private static final Expr f001575 = Expr.makeLambda(\"o\", f001574, f001573);\n  private static final Expr f001576 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"None\", f000647),\n            new SimpleImmutableEntry<String, Expr>(\"Some\", f000013)\n          });\n  private static final Expr f001577 = Expr.makeMerge(f001576, f000836, null);\n  private static final Expr f001578 = Expr.makeLambda(\"o\", f001002, f001577);\n  private static final Expr f001579 = Expr.makeLambda(\"f\", f001538, f001578);\n  private static final Expr f001580 = Expr.makeLambda(\"a\", f000019, f001579);\n  private static final Expr f001581 = Expr.makePi(\"_\", f000226, f000226);\n  private static final Expr f001582 = Expr.makeTextLiteral(\"A\");\n  private static final Expr f001583 = Expr.makeTextLiteral(\"a\");\n  private static final Expr f001584 = Expr.makeApplication(f000528, new Expr[] {f001582, f001583});\n  private static final Expr f001585 = Expr.makeTextLiteral(\"B\");\n  private static final Expr f001586 = Expr.makeTextLiteral(\"b\");\n  private static final Expr f001587 = Expr.makeApplication(f000528, new Expr[] {f001585, f001586});\n  private static final Expr f001588 = Expr.makeTextLiteral(\"C\");\n  private static final Expr f001589 = Expr.makeTextLiteral(\"c\");\n  private static final Expr f001590 = Expr.makeApplication(f000528, new Expr[] {f001588, f001589});\n  private static final Expr f001591 = Expr.makeTextLiteral(\"D\");\n  private static final Expr f001592 = Expr.makeTextLiteral(\"d\");\n  private static final Expr f001593 = Expr.makeApplication(f000528, new Expr[] {f001591, f001592});\n  private static final Expr f001594 = Expr.makeTextLiteral(\"E\");\n  private static final Expr f001595 = Expr.makeTextLiteral(\"e\");\n  private static final Expr f001596 = Expr.makeApplication(f000528, new Expr[] {f001594, f001595});\n  private static final Expr f001597 = Expr.makeTextLiteral(\"F\");\n  private static final Expr f001598 = Expr.makeTextLiteral(\"f\");\n  private static final Expr f001599 = Expr.makeApplication(f000528, new Expr[] {f001597, f001598});\n  private static final Expr f001600 = Expr.makeTextLiteral(\"G\");\n  private static final Expr f001601 = Expr.makeTextLiteral(\"g\");\n  private static final Expr f001602 = Expr.makeApplication(f000528, new Expr[] {f001600, f001601});\n  private static final Expr f001603 = Expr.makeTextLiteral(\"H\");\n  private static final Expr f001604 = Expr.makeTextLiteral(\"h\");\n  private static final Expr f001605 = Expr.makeApplication(f000528, new Expr[] {f001603, f001604});\n  private static final Expr f001606 = Expr.makeTextLiteral(\"I\");\n  private static final Expr f001607 = Expr.makeTextLiteral(\"i\");\n  private static final Expr f001608 = Expr.makeApplication(f000528, new Expr[] {f001606, f001607});\n  private static final Expr f001609 = Expr.makeTextLiteral(\"J\");\n  private static final Expr f001610 = Expr.makeTextLiteral(\"j\");\n  private static final Expr f001611 = Expr.makeApplication(f000528, new Expr[] {f001609, f001610});\n  private static final Expr f001612 = Expr.makeTextLiteral(\"K\");\n  private static final Expr f001613 = Expr.makeTextLiteral(\"k\");\n  private static final Expr f001614 = Expr.makeApplication(f000528, new Expr[] {f001612, f001613});\n  private static final Expr f001615 = Expr.makeTextLiteral(\"L\");\n  private static final Expr f001616 = Expr.makeTextLiteral(\"l\");\n  private static final Expr f001617 = Expr.makeApplication(f000528, new Expr[] {f001615, f001616});\n  private static final Expr f001618 = Expr.makeTextLiteral(\"M\");\n  private static final Expr f001619 = Expr.makeTextLiteral(\"m\");\n  private static final Expr f001620 = Expr.makeApplication(f000528, new Expr[] {f001618, f001619});\n  private static final Expr f001621 = Expr.makeTextLiteral(\"N\");\n  private static final Expr f001622 = Expr.makeTextLiteral(\"n\");\n  private static final Expr f001623 = Expr.makeApplication(f000528, new Expr[] {f001621, f001622});\n  private static final Expr f001624 = Expr.makeTextLiteral(\"O\");\n  private static final Expr f001625 = Expr.makeTextLiteral(\"o\");\n  private static final Expr f001626 = Expr.makeApplication(f000528, new Expr[] {f001624, f001625});\n  private static final Expr f001627 = Expr.makeTextLiteral(\"P\");\n  private static final Expr f001628 = Expr.makeTextLiteral(\"p\");\n  private static final Expr f001629 = Expr.makeApplication(f000528, new Expr[] {f001627, f001628});\n  private static final Expr f001630 = Expr.makeTextLiteral(\"Q\");\n  private static final Expr f001631 = Expr.makeTextLiteral(\"q\");\n  private static final Expr f001632 = Expr.makeApplication(f000528, new Expr[] {f001630, f001631});\n  private static final Expr f001633 = Expr.makeTextLiteral(\"R\");\n  private static final Expr f001634 = Expr.makeTextLiteral(\"r\");\n  private static final Expr f001635 = Expr.makeApplication(f000528, new Expr[] {f001633, f001634});\n  private static final Expr f001636 = Expr.makeTextLiteral(\"S\");\n  private static final Expr f001637 = Expr.makeTextLiteral(\"s\");\n  private static final Expr f001638 = Expr.makeApplication(f000528, new Expr[] {f001636, f001637});\n  private static final Expr f001639 = Expr.makeTextLiteral(\"T\");\n  private static final Expr f001640 = Expr.makeTextLiteral(\"t\");\n  private static final Expr f001641 = Expr.makeApplication(f000528, new Expr[] {f001639, f001640});\n  private static final Expr f001642 = Expr.makeTextLiteral(\"U\");\n  private static final Expr f001643 = Expr.makeTextLiteral(\"u\");\n  private static final Expr f001644 = Expr.makeApplication(f000528, new Expr[] {f001642, f001643});\n  private static final Expr f001645 = Expr.makeTextLiteral(\"V\");\n  private static final Expr f001646 = Expr.makeTextLiteral(\"v\");\n  private static final Expr f001647 = Expr.makeApplication(f000528, new Expr[] {f001645, f001646});\n  private static final Expr f001648 = Expr.makeTextLiteral(\"W\");\n  private static final Expr f001649 = Expr.makeTextLiteral(\"w\");\n  private static final Expr f001650 = Expr.makeApplication(f000528, new Expr[] {f001648, f001649});\n  private static final Expr f001651 = Expr.makeTextLiteral(\"X\");\n  private static final Expr f001652 = Expr.makeTextLiteral(\"x\");\n  private static final Expr f001653 = Expr.makeApplication(f000528, new Expr[] {f001651, f001652});\n  private static final Expr f001654 = Expr.makeTextLiteral(\"Y\");\n  private static final Expr f001655 = Expr.makeTextLiteral(\"y\");\n  private static final Expr f001656 = Expr.makeApplication(f000528, new Expr[] {f001654, f001655});\n  private static final Expr f001657 = Expr.makeTextLiteral(\"Z\");\n  private static final Expr f001658 = Expr.makeTextLiteral(\"z\");\n  private static final Expr f001659 = Expr.makeApplication(f000528, new Expr[] {f001657, f001658});\n  private static final Expr f001660 =\n      Expr.makeNonEmptyListLiteral(\n          new Expr[] {\n            f001584, f001587, f001590, f001593, f001596, f001599, f001602, f001605, f001608,\n            f001611, f001614, f001617, f001620, f001623, f001626, f001629, f001632, f001635,\n            f001638, f001641, f001644, f001647, f001650, f001653, f001656, f001659\n          });\n  private static final Expr f001661 = Expr.makeIdentifier(\"replacement\", 0);\n  private static final Expr f001662 = Expr.makeLambda(\"replacement\", f001581, f001661);\n  private static final Expr f001663 =\n      Expr.makeApplication(f000000, new Expr[] {f001581, f001660, f000226, f001662});\n  private static final Expr f001664 = Expr.makeIdentifier(\"num\", 0);\n  private static final Expr f001665 = Expr.makeIdentifier(\"text\", 0);\n  private static final Expr f001666 = Expr.makeNonEmptyListLiteral(new Expr[] {f001665});\n  private static final Expr f001667 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001666, f000248);\n  private static final Expr f001668 = Expr.makeLambda(\"as\", f000357, f001667);\n  private static final Expr f001669 =\n      Expr.makeApplication(f000884, new Expr[] {f001664, f000357, f001668, f000360});\n  private static final Expr f001670 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f001669, f000226, f001530, f000647});\n  private static final Expr f001671 = Expr.makeLambda(\"text\", f000226, f001670);\n  private static final Expr f001672 = Expr.makeLambda(\"num\", f000221, f001671);\n  private static final Expr f001673 = Expr.makeTextLiteral(\" \");\n  private static final Expr f001674 = Expr.makeNonEmptyListLiteral(new Expr[] {f001673});\n  private static final Expr f001675 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001674, f000248);\n  private static final Expr f001676 = Expr.makeLambda(\"as\", f000357, f001675);\n  private static final Expr f001677 =\n      Expr.makeApplication(f000884, new Expr[] {f000070, f000357, f001676, f000360});\n  private static final Expr f001678 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f001677, f000226, f001530, f000647});\n  private static final Expr f001679 = Expr.makeLambda(\"a\", f000221, f001678);\n  private static final Expr f001680 = Expr.makeApplication(f000528, new Expr[] {f001583, f001582});\n  private static final Expr f001681 = Expr.makeApplication(f000528, new Expr[] {f001586, f001585});\n  private static final Expr f001682 = Expr.makeApplication(f000528, new Expr[] {f001589, f001588});\n  private static final Expr f001683 = Expr.makeApplication(f000528, new Expr[] {f001592, f001591});\n  private static final Expr f001684 = Expr.makeApplication(f000528, new Expr[] {f001595, f001594});\n  private static final Expr f001685 = Expr.makeApplication(f000528, new Expr[] {f001598, f001597});\n  private static final Expr f001686 = Expr.makeApplication(f000528, new Expr[] {f001601, f001600});\n  private static final Expr f001687 = Expr.makeApplication(f000528, new Expr[] {f001604, f001603});\n  private static final Expr f001688 = Expr.makeApplication(f000528, new Expr[] {f001607, f001606});\n  private static final Expr f001689 = Expr.makeApplication(f000528, new Expr[] {f001610, f001609});\n  private static final Expr f001690 = Expr.makeApplication(f000528, new Expr[] {f001613, f001612});\n  private static final Expr f001691 = Expr.makeApplication(f000528, new Expr[] {f001616, f001615});\n  private static final Expr f001692 = Expr.makeApplication(f000528, new Expr[] {f001619, f001618});\n  private static final Expr f001693 = Expr.makeApplication(f000528, new Expr[] {f001622, f001621});\n  private static final Expr f001694 = Expr.makeApplication(f000528, new Expr[] {f001625, f001624});\n  private static final Expr f001695 = Expr.makeApplication(f000528, new Expr[] {f001628, f001627});\n  private static final Expr f001696 = Expr.makeApplication(f000528, new Expr[] {f001631, f001630});\n  private static final Expr f001697 = Expr.makeApplication(f000528, new Expr[] {f001634, f001633});\n  private static final Expr f001698 = Expr.makeApplication(f000528, new Expr[] {f001637, f001636});\n  private static final Expr f001699 = Expr.makeApplication(f000528, new Expr[] {f001640, f001639});\n  private static final Expr f001700 = Expr.makeApplication(f000528, new Expr[] {f001643, f001642});\n  private static final Expr f001701 = Expr.makeApplication(f000528, new Expr[] {f001646, f001645});\n  private static final Expr f001702 = Expr.makeApplication(f000528, new Expr[] {f001649, f001648});\n  private static final Expr f001703 = Expr.makeApplication(f000528, new Expr[] {f001652, f001651});\n  private static final Expr f001704 = Expr.makeApplication(f000528, new Expr[] {f001655, f001654});\n  private static final Expr f001705 = Expr.makeApplication(f000528, new Expr[] {f001658, f001657});\n  private static final Expr f001706 =\n      Expr.makeNonEmptyListLiteral(\n          new Expr[] {\n            f001680, f001681, f001682, f001683, f001684, f001685, f001686, f001687, f001688,\n            f001689, f001690, f001691, f001692, f001693, f001694, f001695, f001696, f001697,\n            f001698, f001699, f001700, f001701, f001702, f001703, f001704, f001705\n          });\n  private static final Expr f001707 =\n      Expr.makeApplication(f000000, new Expr[] {f001581, f001706, f000226, f001662});\n  private static final Expr f001708 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"concat\", f001532),\n            new SimpleImmutableEntry<String, Expr>(\"concatMap\", f001540),\n            new SimpleImmutableEntry<String, Expr>(\"concatMapSep\", f001556),\n            new SimpleImmutableEntry<String, Expr>(\"concatSep\", f001569),\n            new SimpleImmutableEntry<String, Expr>(\"default\", f001575),\n            new SimpleImmutableEntry<String, Expr>(\"defaultMap\", f001580),\n            new SimpleImmutableEntry<String, Expr>(\"lowerASCII\", f001663),\n            new SimpleImmutableEntry<String, Expr>(\"replace\", f000528),\n            new SimpleImmutableEntry<String, Expr>(\"replicate\", f001672),\n            new SimpleImmutableEntry<String, Expr>(\"show\", f000682),\n            new SimpleImmutableEntry<String, Expr>(\"spaces\", f001679),\n            new SimpleImmutableEntry<String, Expr>(\"upperASCII\", f001707)\n          });\n  private static final Expr f001709 = Expr.makeIdentifier(\"XML\", 0);\n  private static final Expr f001710 = Expr.makeApplication(f000010, new Expr[] {f001709});\n  private static final Expr f001711 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"attributes\", f000696),\n            new SimpleImmutableEntry<String, Expr>(\"content\", f001710),\n            new SimpleImmutableEntry<String, Expr>(\"name\", f000226)\n          });\n  private static final Expr f001712 = Expr.makePi(\"_\", f001711, f001709);\n  private static final Expr f001713 = Expr.makePi(\"_\", f000226, f001709);\n  private static final Expr f001714 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"element\", f001712),\n            new SimpleImmutableEntry<String, Expr>(\"text\", f001713)\n          });\n  private static final Expr f001715 = Expr.makePi(\"xml\", f001714, f001709);\n  private static final Expr f001716 = Expr.makePi(\"XML\", f000019, f001715);\n  private static final Expr f001717 = Expr.makeIdentifier(\"xml\", 0);\n  private static final Expr f001718 = Expr.makeFieldAccess(f001717, \"element\");\n  private static final Expr f001719 = Expr.makeIdentifier(\"elem\", 0);\n  private static final Expr f001720 = Expr.makeFieldAccess(f001719, \"attributes\");\n  private static final Expr f001721 = Expr.makeFieldAccess(f001719, \"content\");\n  private static final Expr f001722 = Expr.makeApplication(f000022, new Expr[] {f001709, f001717});\n  private static final Expr f001723 = Expr.makeNonEmptyListLiteral(new Expr[] {f001722});\n  private static final Expr f001724 =\n      Expr.makeOperatorApplication(Operator.LIST_APPEND, f001723, f000248);\n  private static final Expr f001725 = Expr.makeLambda(\"as\", f001710, f001724);\n  private static final Expr f001726 = Expr.makeLambda(\"x\", f001716, f001725);\n  private static final Expr f001727 = Expr.makeEmptyListLiteral(f001710);\n  private static final Expr f001728 =\n      Expr.makeApplication(f000000, new Expr[] {f001716, f001721, f001710, f001726, f001727});\n  private static final Expr f001729 = Expr.makeFieldAccess(f001719, \"name\");\n  private static final Expr f001730 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"attributes\", f001720),\n            new SimpleImmutableEntry<String, Expr>(\"content\", f001728),\n            new SimpleImmutableEntry<String, Expr>(\"name\", f001729)\n          });\n  private static final Expr f001731 = Expr.makeApplication(f001718, new Expr[] {f001730});\n  private static final Expr f001732 = Expr.makeLambda(\"xml\", f001714, f001731);\n  private static final Expr f001733 = Expr.makeLambda(\"XML\", f000019, f001732);\n  private static final Expr f001734 = Expr.makeApplication(f000010, new Expr[] {f001716});\n  private static final Expr f001735 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"attributes\", f000696),\n            new SimpleImmutableEntry<String, Expr>(\"content\", f001734),\n            new SimpleImmutableEntry<String, Expr>(\"name\", f000226)\n          });\n  private static final Expr f001736 = Expr.makeLambda(\"elem\", f001735, f001733);\n  private static final Expr f001737 = Expr.makeEmptyListLiteral(f000696);\n  private static final Expr f001738 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"attributes\", f001720),\n            new SimpleImmutableEntry<String, Expr>(\"content\", f001727),\n            new SimpleImmutableEntry<String, Expr>(\"name\", f001729)\n          });\n  private static final Expr f001739 = Expr.makeApplication(f001718, new Expr[] {f001738});\n  private static final Expr f001740 = Expr.makeLambda(\"xml\", f001714, f001739);\n  private static final Expr f001741 = Expr.makeLambda(\"XML\", f000019, f001740);\n  private static final Expr f001742 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"attributes\", f000696),\n            new SimpleImmutableEntry<String, Expr>(\"name\", f000226)\n          });\n  private static final Expr f001743 = Expr.makeLambda(\"elem\", f001742, f001741);\n  private static final Expr f001744 = Expr.makeTextLiteral(\"&quot;\");\n  private static final Expr f001745 = Expr.makeTextLiteral(\"'\");\n  private static final Expr f001746 = Expr.makeTextLiteral(\"&apos;\");\n  private static final Expr f001747 = Expr.makeTextLiteral(\"<\");\n  private static final Expr f001748 = Expr.makeTextLiteral(\"&lt;\");\n  private static final Expr f001749 = Expr.makeTextLiteral(\"&\");\n  private static final Expr f001750 = Expr.makeTextLiteral(\"&amp;\");\n  private static final Expr f001751 =\n      Expr.makeApplication(f000528, new Expr[] {f001749, f001750, f000294});\n  private static final Expr f001752 =\n      Expr.makeApplication(f000528, new Expr[] {f001747, f001748, f001751});\n  private static final Expr f001753 =\n      Expr.makeApplication(f000528, new Expr[] {f001745, f001746, f001752});\n  private static final Expr f001754 =\n      Expr.makeApplication(f000528, new Expr[] {f000529, f001744, f001753});\n  private static final Expr f001755 =\n      Expr.makeTextLiteral(\n          new String[] {\" \", \"=\\\"\", \"\\\"\", \"\"}, new Expr[] {f000293, f001754, f000023});\n  private static final Expr f001756 = Expr.makeLambda(\"y\", f000226, f001755);\n  private static final Expr f001757 = Expr.makeLambda(\"x\", f000681, f001756);\n  private static final Expr f001758 =\n      Expr.makeApplication(f000000, new Expr[] {f000681, f001720, f000226, f001757, f000647});\n  private static final Expr f001759 = Expr.makeApplication(f000921, new Expr[] {f000226, f001721});\n  private static final Expr f001760 = Expr.makeApplication(f000074, new Expr[] {f001759});\n  private static final Expr f001761 = Expr.makeTextLiteral(\"/>\");\n  private static final Expr f001762 =\n      Expr.makeApplication(f000000, new Expr[] {f000226, f001721, f000226, f001530, f000647});\n  private static final Expr f001763 =\n      Expr.makeTextLiteral(new String[] {\">\", \"</\", \">\"}, new Expr[] {f001762, f001729});\n  private static final Expr f001764 = Expr.makeIf(f001760, f001761, f001763);\n  private static final Expr f001765 =\n      Expr.makeTextLiteral(new String[] {\"<\", \"\", \"\", \"\"}, new Expr[] {f001729, f001758, f001764});\n  private static final Expr f001766 =\n      Expr.makeRecordType(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"attributes\", f000696),\n            new SimpleImmutableEntry<String, Expr>(\"content\", f000357),\n            new SimpleImmutableEntry<String, Expr>(\"name\", f000226)\n          });\n  private static final Expr f001767 = Expr.makeLambda(\"elem\", f001766, f001765);\n  private static final Expr f001768 = Expr.makeTextLiteral(\">\");\n  private static final Expr f001769 = Expr.makeTextLiteral(\"&gt;\");\n  private static final Expr f001770 =\n      Expr.makeApplication(f000528, new Expr[] {f001749, f001750, f001665});\n  private static final Expr f001771 =\n      Expr.makeApplication(f000528, new Expr[] {f001747, f001748, f001770});\n  private static final Expr f001772 =\n      Expr.makeApplication(f000528, new Expr[] {f001768, f001769, f001771});\n  private static final Expr f001773 = Expr.makeLambda(\"text\", f000226, f001772);\n  private static final Expr f001774 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"element\", f001767),\n            new SimpleImmutableEntry<String, Expr>(\"text\", f001773)\n          });\n  private static final Expr f001775 = Expr.makeApplication(f000022, new Expr[] {f000226, f001774});\n  private static final Expr f001776 = Expr.makeLambda(\"x\", f001716, f001775);\n  private static final Expr f001777 = Expr.makeFieldAccess(f001717, \"text\");\n  private static final Expr f001778 = Expr.makeIdentifier(\"d\", 0);\n  private static final Expr f001779 = Expr.makeApplication(f001777, new Expr[] {f001778});\n  private static final Expr f001780 = Expr.makeLambda(\"xml\", f001714, f001779);\n  private static final Expr f001781 = Expr.makeLambda(\"XML\", f000019, f001780);\n  private static final Expr f001782 = Expr.makeLambda(\"d\", f000226, f001781);\n  private static final Expr f001783 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Type\", f001716),\n            new SimpleImmutableEntry<String, Expr>(\"attribute\", f000278),\n            new SimpleImmutableEntry<String, Expr>(\"element\", f001736),\n            new SimpleImmutableEntry<String, Expr>(\"emptyAttributes\", f001737),\n            new SimpleImmutableEntry<String, Expr>(\"leaf\", f001743),\n            new SimpleImmutableEntry<String, Expr>(\"render\", f001776),\n            new SimpleImmutableEntry<String, Expr>(\"text\", f001782)\n          });\n  private static final Expr f001784 =\n      Expr.makeRecordLiteral(\n          new Entry[] {\n            new SimpleImmutableEntry<String, Expr>(\"Bool\", f000053),\n            new SimpleImmutableEntry<String, Expr>(\"Double\", f000055),\n            new SimpleImmutableEntry<String, Expr>(\"Function\", f000073),\n            new SimpleImmutableEntry<String, Expr>(\"Integer\", f000225),\n            new SimpleImmutableEntry<String, Expr>(\"JSON\", f000790),\n            new SimpleImmutableEntry<String, Expr>(\"List\", f001057),\n            new SimpleImmutableEntry<String, Expr>(\"Location\", f001059),\n            new SimpleImmutableEntry<String, Expr>(\"Map\", f001123),\n            new SimpleImmutableEntry<String, Expr>(\"Monoid\", f001126),\n            new SimpleImmutableEntry<String, Expr>(\"Natural\", f001226),\n            new SimpleImmutableEntry<String, Expr>(\"NonEmpty\", f001391),\n            new SimpleImmutableEntry<String, Expr>(\"Operator\", f001419),\n            new SimpleImmutableEntry<String, Expr>(\"Optional\", f001527),\n            new SimpleImmutableEntry<String, Expr>(\"Text\", f001708),\n            new SimpleImmutableEntry<String, Expr>(\"XML\", f001783)\n          });\n\n  public static final Expr instance = f001784;\n}\n"
  },
  {
    "path": "modules/scala/src/main/scala/org/dhallj/syntax/package.scala",
    "content": "package org.dhallj\n\nimport org.dhallj.core.DhallException.{ParsingFailure, ResolutionFailure}\nimport org.dhallj.core.Expr\nimport org.dhallj.core.typechecking.TypeCheckFailure\nimport org.dhallj.imports.mini.Resolver\nimport org.dhallj.parser.DhallParser\n\npackage object syntax {\n  implicit final class DhallStringOps(val value: String) extends AnyVal {\n    def parseExpr: Either[ParsingFailure, Expr] =\n      try {\n        Right(DhallParser.parse(value))\n      } catch {\n        case e: ParsingFailure => Left(e)\n      }\n  }\n\n  implicit final class DhallExprOps(val expr: Expr) extends AnyVal {\n    def apply(args: Expr*): Expr = Expr.makeApplication(expr, args.toArray)\n\n    def typeCheck: Either[TypeCheckFailure, Expr] =\n      try {\n        Right(Expr.Util.typeCheck(expr))\n      } catch {\n        case e: TypeCheckFailure => Left(e)\n      }\n\n    def diff(other: Expr): Option[(Option[Expr], Option[Expr])] =\n      Option(Expr.Util.getFirstDiff(expr, other)).map(entry => (Option(entry.getKey), Option(entry.getValue)))\n\n    def resolve: Either[ResolutionFailure, Expr] =\n      try {\n        Right(Resolver.resolve(expr))\n      } catch {\n        case e: ResolutionFailure => Left(e)\n      }\n\n  }\n}\n"
  },
  {
    "path": "modules/scala-codec/src/main/scala/org/dhallj/codec/Decoder.scala",
    "content": "package org.dhallj.codec\n\nimport cats.Traverse\nimport cats.instances.either._\nimport cats.instances.vector._\nimport org.dhallj.core.Expr\nimport org.dhallj.core.typechecking.TypeCheckFailure\nimport org.dhallj.ast._\n\ntrait Decoder[A] { self =>\n  def decode(expr: Expr): Decoder.Result[A]\n  def isValidType(typeExpr: Expr): Boolean\n\n  /**\n   * Can any value of this Dhall type be decoded into this Scala type?\n   */\n  def isExactType(typeExpr: Expr): Boolean\n\n  def map[B](f: A => B): Decoder[B] = new Decoder[B] {\n    def decode(expr: Expr): Decoder.Result[B] = self.decode(expr).map(f)\n    def isValidType(typeExpr: Expr): Boolean = self.isValidType(typeExpr)\n    def isExactType(typeExpr: Expr): Boolean = self.isExactType(typeExpr)\n  }\n}\n\nobject Decoder {\n  type Result[A] = Either[DecodingFailure, A]\n\n  def apply[A](implicit A: Decoder[A]): Decoder[A] = A\n\n  implicit val decodeLong: Decoder[Long] = new Decoder[Long] {\n    def decode(expr: Expr): Result[Long] = expr.normalize match {\n      case NaturalLiteral(v) =>\n        if (v <= Long.MaxValue) {\n          Right(v.toLong)\n        } else {\n          Left(new DecodingFailure(\"Long\", expr))\n        }\n      case IntegerLiteral(v) =>\n        if (v <= Long.MaxValue && v >= Long.MinValue) {\n          Right(v.toLong)\n        } else {\n          Left(new DecodingFailure(\"Long\", expr))\n        }\n      case other => Left(new DecodingFailure(\"Long\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean =\n      typeExpr == Expr.Constants.NATURAL || typeExpr == Expr.Constants.INTEGER\n\n    def isExactType(typeExpr: Expr): Boolean = false\n  }\n\n  implicit val decodeInt: Decoder[Int] = new Decoder[Int] {\n    def decode(expr: Expr): Result[Int] = expr.normalize match {\n      case NaturalLiteral(v) =>\n        if (v <= Int.MaxValue) {\n          Right(v.toInt)\n        } else {\n          Left(new DecodingFailure(\"Int\", expr))\n        }\n      case IntegerLiteral(v) =>\n        if (v <= Int.MaxValue && v >= Int.MinValue) {\n          Right(v.toInt)\n        } else {\n          Left(new DecodingFailure(\"Int\", expr))\n        }\n      case other => Left(new DecodingFailure(\"Int\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean =\n      typeExpr == Expr.Constants.NATURAL || typeExpr == Expr.Constants.INTEGER\n\n    def isExactType(typeExpr: Expr): Boolean = false\n  }\n\n  implicit val decodeBigInt: Decoder[BigInt] = new Decoder[BigInt] {\n    def decode(expr: Expr): Result[BigInt] = expr.normalize match {\n      case NaturalLiteral(v) => Right(v)\n      case IntegerLiteral(v) => Right(v)\n      case other             => Left(new DecodingFailure(\"BigInt\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean =\n      typeExpr == Expr.Constants.NATURAL || typeExpr == Expr.Constants.INTEGER\n\n    def isExactType(typeExpr: Expr): Boolean = typeExpr == Expr.Constants.INTEGER\n  }\n\n  implicit val decodeDouble: Decoder[Double] = new Decoder[Double] {\n    def decode(expr: Expr): Result[Double] = expr.normalize match {\n      case DoubleLiteral(v)  => Right(v)\n      case NaturalLiteral(v) => Right(v.toDouble)\n      case IntegerLiteral(v) => Right(v.toDouble)\n      case other             => Left(new DecodingFailure(\"Double\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean =\n      typeExpr == Expr.Constants.DOUBLE ||\n        typeExpr == Expr.Constants.NATURAL ||\n        typeExpr == Expr.Constants.INTEGER\n\n    def isExactType(typeExpr: Expr): Boolean = isValidType(typeExpr)\n  }\n\n  implicit val decodeString: Decoder[String] = new Decoder[String] {\n    def decode(expr: Expr): Result[String] = expr.normalize match {\n      case TextLiteral((v, Vector())) => Right(v)\n      case other                      => Left(new DecodingFailure(\"String\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean = typeExpr == Expr.Constants.TEXT\n    def isExactType(typeExpr: Expr): Boolean = false\n  }\n\n  implicit val decodeBoolean: Decoder[Boolean] = new Decoder[Boolean] {\n    def decode(expr: Expr): Result[Boolean] = expr.normalize match {\n      case BoolLiteral(v) => Right(v)\n      case other          => Left(new DecodingFailure(\"Boolean\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean = typeExpr == Expr.Constants.BOOL\n    def isExactType(typeExpr: Expr): Boolean = isValidType(typeExpr)\n  }\n\n  implicit def decodeOption[A: Decoder]: Decoder[Option[A]] = new Decoder[Option[A]] {\n    def decode(expr: Expr): Result[Option[A]] = expr.normalize match {\n      case Application(Expr.Constants.SOME, value) => Decoder[A].decode(value).map(Some(_))\n      case Application(Expr.Constants.NONE, elementType) if Decoder[A].isValidType(elementType) =>\n        Right(None)\n      case other => Left(new DecodingFailure(\"Optional\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean = typeExpr match {\n      case Application(Expr.Constants.OPTIONAL, elementType) => Decoder[A].isValidType(elementType)\n      case _                                                 => false\n    }\n\n    def isExactType(typeExpr: Expr): Boolean = typeExpr match {\n      case Application(Expr.Constants.OPTIONAL, elementType) => Decoder[A].isExactType(elementType)\n      case _                                                 => false\n    }\n  }\n\n  implicit def decodeVector[A: Decoder]: Decoder[Vector[A]] = new Decoder[Vector[A]] {\n    def decode(expr: Expr): Result[Vector[A]] = expr.normalize match {\n      case NonEmptyListLiteral(values) =>\n        Traverse[Vector].traverse(values)(Decoder[A].decode)\n      case EmptyListLiteral(Application(Expr.Constants.LIST, elementType)) if Decoder[A].isValidType(elementType) =>\n        Right(Vector.empty)\n      case other => Left(new DecodingFailure(\"Vector\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean = typeExpr match {\n      case Application(Expr.Constants.LIST, elementType) => Decoder[A].isValidType(elementType)\n      case _                                             => false\n    }\n\n    def isExactType(typeExpr: Expr): Boolean = typeExpr match {\n      case Application(Expr.Constants.LIST, elementType) => Decoder[A].isExactType(elementType)\n      case _                                             => false\n    }\n  }\n\n  implicit def decodeList[A: Decoder]: Decoder[List[A]] = new Decoder[List[A]] {\n    def decode(expr: Expr): Result[List[A]] = expr.normalize match {\n      case NonEmptyListLiteral(values) =>\n        Traverse[Vector].traverse(values)(Decoder[A].decode).map(_.toList)\n      case EmptyListLiteral(Application(Expr.Constants.LIST, elementType)) if Decoder[A].isValidType(elementType) =>\n        Right(Nil)\n      case other => Left(new DecodingFailure(\"List\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean = typeExpr match {\n      case Application(Expr.Constants.LIST, elementType) => Decoder[A].isValidType(elementType)\n      case _                                             => false\n    }\n\n    def isExactType(typeExpr: Expr): Boolean = typeExpr match {\n      case Application(Expr.Constants.LIST, elementType) => Decoder[A].isExactType(elementType)\n      case _                                             => false\n    }\n  }\n\n  implicit def decodeFunction1[A: Encoder, B: Decoder]: Decoder[A => B] = new Decoder[A => B] {\n    def decode(expr: Expr): Result[A => B] = expr.normalize match {\n      case f @ Lambda(_, inputType, result) if Encoder[A].isExactType(inputType) =>\n        val inferredType =\n          try {\n            Right(Expr.Util.typeCheck(f))\n          } catch {\n            case e: TypeCheckFailure =>\n              Left(new DecodingFailure(\"Function1\", f))\n          }\n\n        inferredType.flatMap {\n          case Pi(_, inputType, outputType)\n              if Encoder[A].isExactType(inputType) && Decoder[B].isExactType(outputType) =>\n            // This is still a little hand-wavy.\n            Right((a: A) => Decoder[B].decode(Application(f, Encoder[A].encode(a)).normalize).toOption.get)\n\n          case _ => Left(new DecodingFailure(\"Function1\", f))\n        }\n\n      case other => Left(new DecodingFailure(\"Function1\", other))\n    }\n\n    def isValidType(typeExpr: Expr): Boolean = typeExpr match {\n      case Pi(_, inputType, outputType) =>\n        Encoder[A].isExactType(inputType) && Decoder[B].isValidType(outputType)\n      case _ => false\n    }\n\n    def isExactType(typeExpr: Expr): Boolean = typeExpr match {\n      case Pi(_, inputType, outputType) =>\n        Encoder[A].isExactType(inputType) && Decoder[B].isExactType(outputType)\n      case _ => false\n    }\n  }\n}\n"
  },
  {
    "path": "modules/scala-codec/src/main/scala/org/dhallj/codec/DecodingFailure.scala",
    "content": "package org.dhallj.codec\n\nimport org.dhallj.core.{DhallException, Expr}\n\nclass DecodingFailure(val target: String, val value: Expr) extends DhallException(s\"Error decoding $target\") {\n  final override def fillInStackTrace(): Throwable = this\n}\n"
  },
  {
    "path": "modules/scala-codec/src/main/scala/org/dhallj/codec/Encoder.scala",
    "content": "package org.dhallj.codec\n\nimport org.dhallj.core.Expr\nimport org.dhallj.ast._\n\ntrait Encoder[A] { self =>\n  def encode(value: A, target: Option[Expr]): Expr\n  def dhallType(value: Option[A], target: Option[Expr]): Expr\n\n  final def encode(value: A): Expr = encode(value, None)\n  final def isExactType(typeExpr: Expr): Boolean = typeExpr == dhallType(None, Some(typeExpr))\n\n  def contramap[B](f: B => A): Encoder[B] = new Encoder[B] {\n    def encode(value: B, target: Option[Expr]): Expr = self.encode(f(value), target)\n    def dhallType(value: Option[B], target: Option[Expr]): Expr =\n      self.dhallType(value.map(f), target)\n  }\n}\n\nobject Encoder {\n  def apply[A](implicit A: Encoder[A]): Encoder[A] = A\n\n  implicit val encodeLong: Encoder[Long] = new Encoder[Long] {\n    def encode(value: Long, target: Option[Expr]): Expr = {\n      val asBigInt = BigInt(value)\n\n      target match {\n        case Some(Expr.Constants.INTEGER) => IntegerLiteral(asBigInt)\n        case _                            => NaturalLiteral(asBigInt).getOrElse(IntegerLiteral(asBigInt))\n      }\n    }\n\n    def dhallType(value: Option[Long], target: Option[Expr]): Expr = target match {\n      case Some(Expr.Constants.INTEGER) => Expr.Constants.INTEGER\n      case _ =>\n        value match {\n          case Some(v) if v < 0 => Expr.Constants.INTEGER\n          case _                => Expr.Constants.NATURAL\n        }\n    }\n  }\n\n  implicit val encodeInt: Encoder[Int] = encodeLong.contramap(_.toLong)\n\n  implicit val encodeBigInt: Encoder[BigInt] = new Encoder[BigInt] {\n    def encode(value: BigInt, target: Option[Expr]): Expr = target match {\n      case Some(Expr.Constants.INTEGER) => IntegerLiteral(value)\n      case _                            => NaturalLiteral(value).getOrElse(IntegerLiteral(value))\n    }\n\n    def dhallType(value: Option[BigInt], target: Option[Expr]): Expr = target match {\n      case Some(Expr.Constants.INTEGER) => Expr.Constants.INTEGER\n      case _ =>\n        value match {\n          case Some(v) if v < 0 => Expr.Constants.INTEGER\n          case _                => Expr.Constants.NATURAL\n        }\n    }\n  }\n\n  implicit val encodeDouble: Encoder[Double] = new Encoder[Double] {\n    def encode(value: Double, target: Option[Expr]): Expr = DoubleLiteral(value)\n    def dhallType(value: Option[Double], target: Option[Expr]): Expr = Expr.Constants.DOUBLE\n  }\n\n  implicit val encodeString: Encoder[String] = new Encoder[String] {\n    def encode(value: String, target: Option[Expr]): Expr = TextLiteral(value)\n    def dhallType(value: Option[String], target: Option[Expr]): Expr = Expr.Constants.TEXT\n  }\n\n  implicit val encodeBoolean: Encoder[Boolean] = new Encoder[Boolean] {\n    def encode(value: Boolean, target: Option[Expr]): Expr = BoolLiteral(value)\n    def dhallType(value: Option[Boolean], target: Option[Expr]): Expr = Expr.Constants.BOOL\n  }\n\n  implicit def encodeOption[A: Encoder]: Encoder[Option[A]] = new Encoder[Option[A]] {\n    def encode(value: Option[A], target: Option[Expr]): Expr = target match {\n      case Some(Application(Expr.Constants.OPTIONAL, elementType)) =>\n        value match {\n          case Some(a) => Application(Expr.Constants.SOME, Encoder[A].encode(a, Some(elementType)))\n          case None =>\n            Application(Expr.Constants.NONE, Encoder[A].dhallType(None, Some(elementType)))\n        }\n      case _ =>\n        value match {\n          case Some(a) => Application(Expr.Constants.SOME, Encoder[A].encode(a))\n          case None =>\n            Application(Expr.Constants.NONE, Encoder[A].dhallType(None, None))\n        }\n    }\n\n    def dhallType(value: Option[Option[A]], target: Option[Expr]): Expr = {\n      val targetElementType = target.flatMap {\n        case Application(Expr.Constants.OPTIONAL, elementType) => Some(elementType)\n        case _                                                 => None\n      }\n\n      Application(Expr.Constants.OPTIONAL, Encoder[A].dhallType(value.flatten, targetElementType))\n    }\n  }\n\n  implicit def encodeVector[A: Encoder]: Encoder[Vector[A]] = new Encoder[Vector[A]] {\n    def encode(value: Vector[A], target: Option[Expr]): Expr = {\n      val tpe = dhallElementType(Some(value), target)\n\n      value match {\n        case Vector() => EmptyListLiteral(Application(Expr.Constants.LIST, tpe))\n        case h +: t =>\n          NonEmptyListLiteral(\n            Encoder[A].encode(h, Some(tpe)),\n            t.map(Encoder[A].encode(_, Some(tpe)))\n          )\n      }\n    }\n\n    private def dhallElementType(value: Option[Vector[A]], target: Option[Expr]): Expr = {\n      val targetElementType = target.flatMap {\n        case Application(Expr.Constants.LIST, elementType) => Some(elementType)\n        case _                                             => None\n      }\n\n      value match {\n        case None           => Encoder[A].dhallType(None, targetElementType)\n        case Some(Vector()) => Encoder[A].dhallType(None, targetElementType)\n        case Some(h +: t) =>\n          t.foldLeft(Encoder[A].dhallType(Some(h), targetElementType)) { case (acc, a) =>\n            Encoder[A].dhallType(Some(a), Some(acc))\n          }\n      }\n    }\n\n    def dhallType(value: Option[Vector[A]], target: Option[Expr]): Expr =\n      Application(Expr.Constants.LIST, dhallElementType(value, target))\n  }\n\n  implicit def encodeList[A: Encoder]: Encoder[List[A]] = encodeVector[A].contramap(_.toVector)\n}\n"
  },
  {
    "path": "modules/scala-codec/src/main/scala/org/dhallj/codec/syntax/package.scala",
    "content": "package org.dhallj.codec\n\nimport org.dhallj.core.Expr\n\npackage object syntax {\n  implicit final class DhallCodecAnyOps[A](val value: A) extends AnyVal {\n    def asExpr(implicit A: Encoder[A]): Expr = A.encode(value)\n  }\n\n  implicit final class DhallCodecExprOps(val expr: Expr) extends AnyVal {\n    def as[A: Decoder]: Decoder.Result[A] = Decoder[A].decode(expr)\n  }\n}\n"
  },
  {
    "path": "modules/scala-codec/src/test/scala/org/dhallj/codec/DecoderSuite.scala",
    "content": "package org.dhallj.codec\n\nimport munit.FunSuite\nimport org.dhallj.codec.syntax._\nimport org.dhallj.syntax._\n\nclass DecoderSuite extends FunSuite() {\n  test(\"Decoder[Vector[String]] decodes non-empty List Text\") {\n    val Right(parsed) = \"\"\"[ \"abc\" , \"def\" ] : List Text\"\"\".parseExpr\n    assertEquals(parsed.as[Vector[String]], Right(Vector(\"abc\", \"def\")))\n  }\n\n  test(\"Decoder[Vector[String]] decodes empty List Text\") {\n    val Right(parsed) = \"[] : List Text\".parseExpr\n    assertEquals(parsed.as[Vector[String]], Right(Vector.empty[String]))\n  }\n\n  test(\"Decoder[List[String]] decodes non-empty List Text\") {\n    val Right(parsed) = \"\"\"[ \"abc\" , \"def\" ] : List Text\"\"\".parseExpr\n    assertEquals(parsed.as[List[String]], Right(List(\"abc\", \"def\")))\n  }\n\n  test(\"Decoder[List[String]] decodes empty List Text\") {\n    val Right(parsed) = \"[] : List Text\".parseExpr\n    assertEquals(parsed.as[List[String]], Right(List.empty[String]))\n  }\n\n  test(\"Decoder[Option[String]] decodes non-empty Optional Text\") {\n    val Right(parsed) = \"\"\"Some \"abc\" : Optional Text\"\"\".parseExpr\n    assertEquals(parsed.as[Option[String]], Right(Some(\"abc\")))\n  }\n\n  test(\"Decoder[Option[String]] decodes empty Optional Text\") {\n    val Right(parsed) = \"None Text : Optional Text\".parseExpr\n    assertEquals(parsed.as[Option[String]], Right(Option.empty[String]))\n  }\n}\n"
  },
  {
    "path": "modules/testing/src/main/scala/org/dhallj/testing/ArbitraryInstances.scala",
    "content": "package org.dhallj.testing\n\nimport org.dhallj.ast._\nimport org.dhallj.core.{Expr, Operator}\nimport org.scalacheck.{Arbitrary, Gen, Shrink}\n\ntrait ArbitraryInstances {\n  def genNameString: Gen[String]\n  def genTextString: Gen[String]\n  def defaultMaxDepth: Int = 3\n  def defaultMaxInterpolated: Int = 3\n  def defaultMaxFields: Int = 5\n\n  def genValidNameString: Gen[String] = genNameString.map(_.replace(\"`\", \"\")).map {\n    case \"\"    => \"x\"\n    case other => other\n  }\n\n  def isValidName(name: String): Boolean =\n    List('\\u0000', '\\u0001', '`').forall(c => name.indexOf(c.toInt) == -1)\n\n  def genIdentifier: Gen[Expr] =\n    for {\n      name <- genValidNameString\n      index <- Gen.oneOf(Gen.const(0L), Arbitrary.arbitrary[Long].map(_.abs))\n    } yield Identifier(name, index)\n\n  val genOperator: Gen[Operator] = Gen.oneOf(Operator.values())\n\n  def genForType(tpe: Expr): Option[Gen[Expr]] = tpe match {\n    case Expr.Constants.NATURAL => Some(Arbitrary.arbitrary[BigInt].map(value => NaturalLiteral(value.abs).get))\n    case Expr.Constants.INTEGER => Some(Arbitrary.arbitrary[BigInt].map(IntegerLiteral(_)))\n    case Expr.Constants.DOUBLE  => Some(Arbitrary.arbitrary[Double].map(DoubleLiteral(_)))\n    case Expr.Constants.BOOL =>\n      Some(\n        Arbitrary.arbitrary[Boolean].map(value => if (value) Expr.Constants.TRUE else Expr.Constants.FALSE)\n      )\n    case Application(Expr.Constants.LIST, elementType) =>\n      genForType(elementType).map(\n        Gen\n          .buildableOf[Vector[Expr], Expr](_)\n          .map(values =>\n            if (values.isEmpty) {\n              EmptyListLiteral(Application(Expr.Constants.LIST, elementType))\n            } else {\n              NonEmptyListLiteral(values.head, values.tail)\n            }\n          )\n      )\n    case Application(Expr.Constants.OPTIONAL, elementType) =>\n      genForType(elementType).map(genElementType =>\n        Gen.oneOf(\n          genElementType.map(Application(Expr.Constants.SOME, _)),\n          Gen.const(Application(Expr.Constants.NONE, elementType))\n        )\n      )\n    case Expr.Constants.TEXT => Some(genText(defaultMaxDepth))\n    case RecordType(fields) =>\n      Some(\n        fields\n          .foldLeft(Gen.const(Map.empty[String, Expr])) { case (acc, (name, tpe)) =>\n            genForType(tpe) match {\n              case Some(genFieldType) => acc.flatMap(m => genFieldType.map(m.updated(name, _)))\n              case None               => acc\n            }\n          }\n          .map(RecordLiteral(_))\n      )\n    case _ => None\n  }\n\n  def genText(maxDepth: Int): Gen[Expr] =\n    if (maxDepth == 0) genTextString.map(TextLiteral(_))\n    else {\n      Gen.oneOf(\n        genTextString.map(TextLiteral(_)),\n        for {\n          first <- genTextString\n          rest <- Gen.buildableOfN[Vector[(Expr, String)], (Expr, String)](\n            defaultMaxInterpolated,\n            genText(maxDepth - 1).flatMap(interpolated => genTextString.map((interpolated, _)))\n          )\n        } yield TextLiteral(first, rest)\n      )\n    }\n\n  val genType: Gen[Expr] = Gen.oneOf(\n    List(\n      Expr.Constants.NATURAL,\n      Expr.Constants.INTEGER,\n      Expr.Constants.DOUBLE,\n      Expr.Constants.BOOL,\n      Expr.Constants.TEXT\n    )\n  )\n\n  def genType(maxDepth: Int): Gen[Expr] =\n    if (maxDepth == 0) genType\n    else {\n      Gen.oneOf(\n        genType,\n        genType(maxDepth - 1).map(Application(Expr.Constants.LIST, _)),\n        genType(maxDepth - 1).map(Application(Expr.Constants.OPTIONAL, _)),\n        Gen\n          .buildableOfN[Vector[(String, Expr)], (String, Expr)](\n            defaultMaxFields,\n            genValidNameString.flatMap(name => genType(maxDepth - 1).map((name, _)))\n          )\n          .map(fields => RecordType(fields.toMap)),\n        Gen\n          .buildableOfN[Vector[(String, Option[Expr])], (String, Option[Expr])](\n            defaultMaxFields,\n            genValidNameString.flatMap(name => Gen.option(genType(maxDepth - 1)).map((name, _)))\n          )\n          .map(fields => UnionType(fields.toMap))\n      )\n    }\n\n  implicit val arbitraryWellTypedExpr: Arbitrary[WellTypedExpr] = Arbitrary(\n    Gen\n      .oneOf(\n        genType(defaultMaxDepth),\n        genType(defaultMaxDepth).flatMap(tpe => genForType(tpe).getOrElse(genType(defaultMaxDepth)))\n        /* TODO: We should test type annotations.\n      genType(defaultMaxDepth).flatMap(tpe =>\n        genForType(tpe).map(_.map(expr => Annotated(expr, tpe))).getOrElse(genType(defaultMaxDepth))\n      )\n         */\n      )\n      .map(WellTypedExpr(_))\n  )\n\n  def genExpr(maxDepth: Int): Gen[Expr] =\n    if (maxDepth == 0) {\n      arbitraryWellTypedExpr.arbitrary.map(_.value)\n    } else {\n      Gen.oneOf(\n        arbitraryWellTypedExpr.arbitrary.map(_.value),\n        for {\n          operator <- genOperator\n          lhs <- genExpr(maxDepth - 1)\n          rhs <- genExpr(maxDepth - 1)\n        } yield Expr.makeOperatorApplication(operator, lhs, rhs),\n        for {\n          f <- genExpr(maxDepth - 1)\n          arg <- genExpr(maxDepth - 1)\n        } yield Expr.makeApplication(f, arg)\n      )\n    }\n\n  implicit val arbitraryExpr: Arbitrary[Expr] = Arbitrary(genExpr(defaultMaxDepth))\n\n  implicit val shrinkExpr: Shrink[Expr] = Shrink {\n    case NaturalLiteral(value) => Shrink.shrink(value).flatMap(value => NaturalLiteral(value.abs))\n    case IntegerLiteral(value) => Shrink.shrink(value).map(IntegerLiteral(_))\n    case DoubleLiteral(value)  => Shrink.shrink(value).map(DoubleLiteral(_))\n    case RecordLiteral(fields) => safeFieldsShrink.shrink(fields).map(RecordLiteral(_))\n    case RecordType(fields)    => safeFieldsShrink.shrink(fields).map(RecordType(_))\n    case UnionType(fields)     => safeOptionFieldsShrink.shrink(fields).map(UnionType(_))\n    case TextLiteral(first, rest) =>\n      Shrink.shrink(first).zip(Shrink.shrink(rest)).map { case (shrunkFirst, shrunkRest) =>\n        TextLiteral(shrunkFirst, shrunkRest)\n      }\n    case Application(Expr.Constants.SOME, arg) => Shrink.shrink(arg).map(Application(Expr.Constants.SOME, _))\n    case NonEmptyListLiteral(values) =>\n      Shrink.shrink(values).filter(_.nonEmpty).map(values => NonEmptyListLiteral(values.head, values.tail))\n    // The following match doesn't preserve type, but is useful for isolating parsing issues for now.\n    case OperatorApplication(_, lhs, rhs) => Stream(lhs, rhs)\n    case other                            => Stream.empty\n  }\n\n  implicit val shrinkWellTypedExpr: Shrink[WellTypedExpr] = Shrink.xmap[Expr, WellTypedExpr](WellTypedExpr(_), _.value)\n\n  val safeNameShrink: Shrink[String] = Shrink(name => name.inits.toStream.init)\n\n  lazy val safeFieldsShrink: Shrink[Map[String, Expr]] = Shrink.shrinkContainer2[Map, String, Expr](\n    implicitly,\n    Shrink.shrinkTuple2(safeNameShrink, shrinkExpr),\n    implicitly\n  )\n\n  lazy val safeOptionFieldsShrink: Shrink[Map[String, Option[Expr]]] =\n    Shrink.shrinkContainer2[Map, String, Option[Expr]](\n      implicitly,\n      Shrink.shrinkTuple2(safeNameShrink, Shrink.shrinkOption(shrinkExpr)),\n      implicitly\n    )\n}\n"
  },
  {
    "path": "modules/testing/src/main/scala/org/dhallj/testing/WellTypedExpr.scala",
    "content": "package org.dhallj.testing\n\nimport org.dhallj.core.Expr\n\ncase class WellTypedExpr(value: Expr)\n"
  },
  {
    "path": "modules/testing/src/main/scala/org/dhallj/testing/package.scala",
    "content": "package org.dhallj.testing\n\nimport org.scalacheck.Gen\n\npackage object instances extends ArbitraryInstances {\n  def genNameString: Gen[String] = Gen.alphaStr\n  def genTextString: Gen[String] = Gen.alphaStr\n}\n"
  },
  {
    "path": "modules/yaml/src/main/java/org/dhallj/yaml/YamlContext.java",
    "content": "package org.dhallj.yaml;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\ninterface YamlContext {\n  void add(String key);\n\n  void add(Object value);\n\n  Object getResult();\n}\n\nfinal class RootContext implements YamlContext {\n  private final Object result;\n\n  RootContext(Object result) {\n    this.result = result;\n  }\n\n  public void add(String key) {}\n\n  public void add(Object value) {}\n\n  public Object getResult() {\n    return this.result;\n  }\n}\n\nfinal class ObjectContext implements YamlContext {\n  private String key = null;\n  private final Map<String, Object> fields = new LinkedHashMap<>();\n  private final boolean skipNulls;\n\n  public ObjectContext(boolean skipNulls) {\n    this.skipNulls = skipNulls;\n  }\n\n  public void add(String key) {\n    this.key = key;\n  }\n\n  public void add(Object value) {\n    if (!skipNulls || value != null) {\n      this.fields.put(this.key, value);\n    } else {\n      this.key = null;\n    }\n  }\n\n  public Object getResult() {\n    return this.fields;\n  }\n}\n\nfinal class ArrayContext implements YamlContext {\n  private final List<Object> values = new ArrayList<>();\n\n  public void add(String key) {}\n\n  public void add(Object value) {\n    this.values.add(value);\n  }\n\n  public Object getResult() {\n    return this.values;\n  }\n}\n"
  },
  {
    "path": "modules/yaml/src/main/java/org/dhallj/yaml/YamlConverter.java",
    "content": "package org.dhallj.yaml;\n\nimport org.dhallj.core.Expr;\nimport org.dhallj.core.converters.JsonConverter;\nimport org.yaml.snakeyaml.Yaml;\nimport org.yaml.snakeyaml.DumperOptions;\n\npublic class YamlConverter {\n  private static final DumperOptions defaultOptions = new DumperOptions();\n\n  static {\n    defaultOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);\n  }\n\n  public static final String toYamlString(Expr expr) {\n    return toYamlString(expr, defaultOptions, true);\n  }\n\n  public static final String toYamlString(Expr expr, DumperOptions options) {\n    return toYamlString(expr, options, true);\n  }\n\n  public static final String toYamlString(Expr expr, boolean skipNulls) {\n    return toYamlString(expr, defaultOptions, skipNulls);\n  }\n\n  public static final String toYamlString(Expr expr, DumperOptions options, boolean skipNulls) {\n    YamlHandler handler = new YamlHandler(skipNulls);\n    boolean wasConverted = expr.accept(new JsonConverter(handler));\n\n    if (wasConverted) {\n      Yaml yaml = new Yaml(options);\n\n      return yaml.dump(handler.getResult());\n    } else {\n      return null;\n    }\n  }\n}\n"
  },
  {
    "path": "modules/yaml/src/main/java/org/dhallj/yaml/YamlHandler.java",
    "content": "package org.dhallj.yaml;\n\nimport java.math.BigInteger;\nimport java.util.ArrayDeque;\nimport java.util.Deque;\nimport org.dhallj.core.converters.JsonHandler;\n\npublic class YamlHandler implements JsonHandler {\n  private final Deque<YamlContext> stack = new ArrayDeque<>();\n  private final boolean skipNulls;\n\n  public YamlHandler(boolean skipNulls) {\n    this.skipNulls = skipNulls;\n  }\n\n  public YamlHandler() {\n    this(true);\n  }\n\n  private final void addValue(Object value) {\n    if (stack.isEmpty()) {\n      stack.push(new RootContext(value));\n    } else {\n      stack.peek().add(value);\n    }\n  }\n\n  public Object getResult() {\n    return this.stack.pop().getResult();\n  }\n\n  public void onNull() {\n    this.addValue(null);\n  }\n\n  public void onBoolean(boolean value) {\n    this.addValue(value);\n  }\n\n  public void onNumber(BigInteger value) {\n    this.addValue(value);\n  }\n\n  public void onDouble(double value) {\n    this.addValue(value);\n  }\n\n  public void onString(String value) {\n    this.addValue(value.replaceAll(\"\\\\\\\\n\", \"\\n\").replaceAll(\"\\\\\\\\\\\"\", \"\\\"\"));\n  }\n\n  public void onArrayStart() {\n    this.stack.push(new ArrayContext());\n  }\n\n  public void onArrayEnd() {\n    YamlContext current = this.stack.pop();\n\n    if (this.stack.isEmpty()) {\n      this.stack.push(current);\n    } else {\n      this.stack.peek().add(current.getResult());\n    }\n  }\n\n  public void onArrayElementGap() {}\n\n  public void onObjectStart() {\n    this.stack.push(new ObjectContext(this.skipNulls));\n  }\n\n  public void onObjectEnd() {\n    YamlContext current = this.stack.pop();\n\n    if (this.stack.isEmpty()) {\n      this.stack.push(current);\n    } else {\n      this.stack.peek().add(current.getResult());\n    }\n  }\n\n  public void onObjectField(String name) {\n    this.stack.peek().add(name);\n  }\n\n  public void onObjectFieldGap() {}\n}\n"
  },
  {
    "path": "modules/yaml/src/test/scala/org/dhallj/yaml/YamlConverterSuite.scala",
    "content": "package org.dhallj.yaml\n\nimport munit.ScalaCheckSuite\nimport org.dhallj.ast._\nimport org.dhallj.core.Expr\nimport org.dhallj.parser.DhallParser\nimport org.scalacheck.Prop\nimport org.yaml.snakeyaml.DumperOptions\n\nclass YamlConverterSuite extends ScalaCheckSuite {\n  property(\"convert integers\") {\n    Prop.forAll { (value: BigInt) =>\n      val asDhall = IntegerLiteral(value.underlying)\n      Option(YamlConverter.toYamlString(asDhall)) == Some(value.toString + \"\\n\")\n    }\n  }\n\n  test(\"convert nested lists\") {\n    val expr = DhallParser.parse(\"[[]: List Bool]\")\n\n    assert(clue(Option(YamlConverter.toYamlString(expr))) == Some(\"- []\\n\"))\n  }\n\n  test(\"convert None\") {\n    val expr = DhallParser.parse(\"None Bool\")\n\n    assert(clue(Option(YamlConverter.toYamlString(expr))) == Some(\"null\\n\"))\n  }\n\n  test(\"convert Some\") {\n    val expr = DhallParser.parse(\"\"\"Some \"foo\"\"\"\")\n\n    assert(clue(Option(YamlConverter.toYamlString(expr))) == Some(\"foo\\n\"))\n  }\n\n  test(\"convert records\") {\n    val expr1 = DhallParser.parse(\"{foo = [{bar = [1]}, {bar = [1, 2, 3]}]}\")\n    val expected =\n      \"\"\"|foo:\n         |- bar:\n         |  - 1\n         |- bar:\n         |  - 1\n         |  - 2\n         |  - 3\n         |\"\"\".stripMargin\n\n    assert(clue(Option(YamlConverter.toYamlString(expr1))) == Some(expected))\n  }\n\n  test(\"convert unions (nullary constructors)\") {\n    val expr1 = DhallParser.parse(\"[((\\\\(x: Natural) -> <foo: Bool|bar>) 1).bar]\").normalize()\n\n    assert(clue(Option(YamlConverter.toYamlString(expr1))) == Some(\"- bar\\n\"))\n  }\n\n  test(\"convert unions\") {\n    val expr1 = DhallParser.parse(\"[<foo: Bool|bar>.foo True]\").normalize()\n\n    assert(clue(Option(YamlConverter.toYamlString(expr1))) == Some(\"- true\\n\"))\n  }\n\n  test(\"convert text containing newlines\") {\n    val expr1 = DhallParser.parse(\"\"\" { a = \"foo\\nbar\" } \"\"\").normalize()\n\n    assert(clue(Option(YamlConverter.toYamlString(expr1))) == Some(\"a: |-\\n  foo\\n  bar\\n\"))\n  }\n\n  test(\"convert test containing quotes\") {\n    val expr1 = DhallParser.parse(\"\"\" { a = \"\\\"\" } \"\"\").normalize()\n    val expr2 = DhallParser.parse(\"\"\" { a = \"\\\"\\n\" } \"\"\").normalize()\n\n    assert(clue(Option(YamlConverter.toYamlString(expr1))) == Some(\"a: '\\\"'\\n\"))\n    assert(clue(Option(YamlConverter.toYamlString(expr2))) == Some(\"a: |\\n  \\\"\\n\"))\n  }\n\n  test(\"convert text containing newlines and respect SnakeYAML configuration\") {\n    val expr1 = DhallParser.parse(\"\"\" { a = \"foo\\nbar\" } \"\"\").normalize()\n    val expected = \"\\\"a\\\": \\\"foo\\\\nbar\\\"\\n\"\n\n    val options = new DumperOptions()\n    options.setDefaultScalarStyle(DumperOptions.ScalarStyle.DOUBLE_QUOTED)\n\n    assert(clue(Option(YamlConverter.toYamlString(expr1, options))) == clue(Some(expected)))\n  }\n\n  test(\"fail safely on unconvertible expressions\") {\n    val expr1 = Lambda(\"x\", Expr.Constants.NATURAL, Identifier(\"x\"))\n\n    assert(Option(YamlConverter.toYamlString(expr1)) == None)\n  }\n}\n"
  },
  {
    "path": "project/build.properties",
    "content": "sbt.version=1.5.5\n"
  },
  {
    "path": "project/plugins.sbt",
    "content": "addSbtPlugin(\"com.codecommit\" % \"sbt-github-actions\" % \"0.13.0\")\naddSbtPlugin(\"com.eed3si9n\" % \"sbt-assembly\" % \"1.1.0\")\naddSbtPlugin(\"com.eed3si9n\" % \"sbt-unidoc\" % \"0.4.3\")\naddSbtPlugin(\"com.github.sbt\" % \"sbt-release\" % \"1.1.0\")\naddSbtPlugin(\"com.github.sbt\" % \"sbt-pgp\" % \"2.1.2\")\naddSbtPlugin(\"com.lightbend.sbt\" % \"sbt-java-formatter\" % \"0.6.1\")\naddSbtPlugin(\"com.typesafe\" % \"sbt-mima-plugin\" % \"1.0.1\")\naddSbtPlugin(\"com.typesafe.sbt\" % \"sbt-ghpages\" % \"0.6.3\")\naddSbtPlugin(\"com.typesafe.sbt\" % \"sbt-git\" % \"1.0.2\")\naddSbtPlugin(\"com.github.sbt\" % \"sbt-native-packager\" % \"1.9.6\")\naddSbtPlugin(\"com.typesafe.sbt\" % \"sbt-site\" % \"1.4.1\")\naddSbtPlugin(\"dev.travisbrown\" % \"sbt-javacc\" % \"0.1.0\")\naddSbtPlugin(\"org.scalameta\" % \"sbt-scalafmt\" % \"2.4.3\")\naddSbtPlugin(\"org.scalastyle\" %% \"scalastyle-sbt-plugin\" % \"1.0.0\")\naddSbtPlugin(\"org.scoverage\" % \"sbt-scoverage\" % \"1.9.1\")\naddSbtPlugin(\"pl.project13.scala\" % \"sbt-jmh\" % \"0.4.3\")\n"
  },
  {
    "path": "scalastyle-config.xml",
    "content": "<scalastyle>\n    <name>Circe Configuration</name>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.EnsureSingleSpaceAfterTokenChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"tokens\">FOR</parameter>\n            <parameter name=\"tokens\">IF</parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.file.FileTabChecker\" enabled=\"true\"></check>\n    <check level=\"warning\" class=\"org.scalastyle.file.FileLengthChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"maxFileLength\"><![CDATA[800]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.file.FileLineLengthChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"maxLineLength\"><![CDATA[140]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.file.WhitespaceEndOfLineChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.ClassNamesChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"regex\"><![CDATA[[A-Z\\~\\*\\/][A-Za-z]*]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.ObjectNamesChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"regex\"><![CDATA[[A-Za-z\\~\\*\\/][A-Za-z]*]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.PackageObjectNamesChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"regex\"><![CDATA[^[a-z][a-z0-9]*$]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.EqualsHashCodeChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.IllegalImportsChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"illegalImports\"><![CDATA[sun._,java.awt._]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.NoWhitespaceBeforeLeftBracketChecker\" enabled=\"true\"></check>\n    <check level=\"warning\" class=\"org.scalastyle.scalariform.NoWhitespaceAfterLeftBracketChecker\" enabled=\"true\"></check>\n    <check level=\"warning\" class=\"org.scalastyle.scalariform.ReturnChecker\" enabled=\"true\"></check>\n    <check level=\"warning\" class=\"org.scalastyle.scalariform.NullChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.NoCloneChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.NoFinalizeChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.CovariantEqualsChecker\" enabled=\"true\"></check>\n    <check level=\"warning\" class=\"org.scalastyle.file.RegexChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"regex\"><![CDATA[println]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.NumberOfTypesChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"maxTypes\"><![CDATA[70]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"warning\" class=\"org.scalastyle.scalariform.CyclomaticComplexityChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"maximum\"><![CDATA[20]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.UppercaseLChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.SimplifyBooleanExpressionChecker\" enabled=\"true\"></check>\n    <check level=\"warning\" class=\"org.scalastyle.scalariform.MethodLengthChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"maxLength\"><![CDATA[50]]></parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" class=\"org.scalastyle.file.NewLineAtEofChecker\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.file.NoNewLineAtEofChecker\" enabled=\"false\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.NotImplementedErrorUsage\" enabled=\"true\"></check>\n    <check level=\"error\" class=\"org.scalastyle.scalariform.PublicMethodsHaveTypeChecker\" enabled=\"true\">\n        <parameters>\n            <parameter name=\"ignoreOverride\">true</parameter>\n        </parameters>\n    </check>\n    <check level=\"error\" enabled=\"false\" class=\"org.scalastyle.scalariform.ImportOrderChecker\">\n        <parameters>\n            <parameter name=\"groups\">all</parameter>\n            <parameter name=\"group.all\">.+</parameter>\n        </parameters>\n    </check>\n</scalastyle>\n"
  },
  {
    "path": "tests/src/main/scala/org/dhallj/tests/HaskellDhall.scala",
    "content": "package org.dhallj.tests\n\nimport java.io.ByteArrayInputStream\nimport java.nio.charset.StandardCharsets.UTF_8\nimport scala.sys.process._\nimport scala.util.Try\n\nclass HaskellDhall {}\nobject HaskellDhall {\n  def isAvailable(): Boolean =\n    Try(Process(\"dhall --version\").lineStream.head.split(\"\\\\.\")).toOption.exists(_.length == 3)\n\n  def hash(input: String): String = {\n    val stream = new ByteArrayInputStream(input.getBytes(UTF_8))\n    Process(\"dhall hash\").#<(stream).lineStream.head.substring(7)\n  }\n\n  def hashFromPath(path: String): String = {\n    Process(s\"dhall hash --file $path\").lineStream.head.substring(7)\n  }\n}\n"
  },
  {
    "path": "tests/src/main/scala/org/dhallj/tests/acceptance/AcceptanceFailureSuite.scala",
    "content": "package org.dhallj.tests.acceptance\n\nimport org.dhallj.core.Expr\nimport org.dhallj.core.binary.Decode.decode\nimport org.dhallj.parser.DhallParser\nimport scala.reflect.ClassTag\n\nabstract class AcceptanceFailureSuite[A, E <: Throwable: ClassTag] extends AcceptanceSuite {\n  override def isInputFileName(fileName: String): Boolean = fileName.endsWith(\".dhall\")\n  override def makeName(inputFileName: String): String = inputFileName.dropRight(6)\n\n  def loadInput(input: Array[Byte]): A\n\n  testInputs\n    .map { case (name, path) =>\n      (name, readBytes(path))\n    }\n    .foreach { case (name, input) =>\n      test(name) {\n        intercept[E](loadInput(input))\n      }\n    }\n}\n\nclass ParsingFailureSuite(val base: String) extends AcceptanceFailureSuite[Expr, Exception] {\n  def loadInput(input: Array[Byte]): Expr = DhallParser.parse(new String(input))\n}\n\nclass TypeCheckingFailureSuite(val base: String) extends AcceptanceFailureSuite[Expr, RuntimeException] {\n  def loadInput(input: Array[Byte]): Expr = Expr.Util.typeCheck(DhallParser.parse(new String(input)))\n}\n\nclass BinaryDecodingFailureSuite(val base: String) extends AcceptanceFailureSuite[Expr, RuntimeException] {\n  override def isInputFileName(fileName: String): Boolean = fileName.endsWith(\".dhallb\")\n\n  def loadInput(input: Array[Byte]): Expr = decode(input)\n}\n"
  },
  {
    "path": "tests/src/main/scala/org/dhallj/tests/acceptance/AcceptanceSuccessSuite.scala",
    "content": "package org.dhallj.tests.acceptance\n\nimport cats.effect.IO\nimport cats.effect.unsafe.IORuntime\nimport java.nio.file.{Files, Path, Paths}\n\nimport org.dhallj.core.Expr\nimport org.dhallj.core.binary.Decode.decode\nimport org.dhallj.parser.DhallParser\n\nimport org.dhallj.imports.{ImportCache, Resolver}\nimport org.http4s.client._\nimport org.http4s.blaze.client._\n\nimport scala.concurrent.ExecutionContext\n\ntrait SuccessSuite[A, B] extends AcceptanceSuite {\n  self: Input[A] =>\n\n  def makeExpectedFilename(input: String): String\n  final private def makeExpectedPath(inputPath: Path): Path =\n    inputPath.resolveSibling(makeExpectedFilename(inputPath.getFileName.toString))\n\n  def transform(input: A): B\n  def loadExpected(input: Array[Byte]): B\n  def compare(result: B, expected: B): Boolean\n\n  def testPairs: List[(String, Path, (String, B))] = testInputs.map { case (name, path) =>\n    (name, path, (readString(path), loadExpected(readBytes(makeExpectedPath(path)))))\n  }\n\n  testPairs.foreach { case (name, path, (input, expected)) =>\n    test(name) {\n      assert(compare(clue(transform(parseInput(path.toString, clue(input)))), clue(expected)))\n    }\n  }\n}\n\ntrait Input[A] {\n  def parseInput(path: String, input: String): A\n\n}\n\ntrait ParsingInput extends Input[Expr] {\n\n  override def parseInput(path: String, input: String): Expr = DhallParser.parse(input)\n\n}\n\ntrait CachedResolvingInput extends Input[Expr] {\n\n  override def parseInput(path: String, input: String): Expr = {\n    val p = Paths.get(path)\n    val parsed = DhallParser.parse(new String(Files.readAllBytes(p)))\n\n    if (parsed.isResolved) parsed\n    else {\n      implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global\n      BlazeClientBuilder[IO](ExecutionContext.global).resource\n        .use { client =>\n          implicit val c: Client[IO] = client\n          Resolver.resolveRelativeTo[IO](p.getParent)(parsed)\n        }\n        .unsafeRunSync()\n    }\n  }\n\n}\n\ntrait ResolvingInput extends Input[Expr] {\n  def parseInput(path: String, input: String): Expr = {\n    val p = Paths.get(path)\n    val parsed = DhallParser.parse(new String(Files.readAllBytes(p)))\n\n    if (parsed.isResolved) parsed\n    else {\n      implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global\n      BlazeClientBuilder[IO](ExecutionContext.global).resource\n        .use { client =>\n          implicit val c: Client[IO] = client\n          Resolver.resolveRelativeTo[IO](new ImportCache.NoopImportCache[IO], new ImportCache.NoopImportCache[IO])(\n            p.getParent\n          )(parsed)\n        }\n        .unsafeRunSync()\n    }\n  }\n}\n\nabstract class ExprOperationAcceptanceSuite(transformation: Expr => Expr) extends SuccessSuite[Expr, Expr] {\n  self: Input[Expr] =>\n\n  def makeExpectedFilename(input: String): String = input.dropRight(7) + \"B.dhall\"\n\n  def transform(input: Expr): Expr = transformation(input)\n\n  def loadExpected(input: Array[Byte]): Expr = DhallParser.parse(new String(input))\n  def compare(result: Expr, expected: Expr): Boolean = result.sameStructure(expected) && result.equivalent(expected)\n}\n\nclass ParsingTypeCheckingSuite(val base: String, override val recurse: Boolean = false)\n    extends ExprOperationAcceptanceSuite(Expr.Util.typeCheck(_))\n    with ParsingInput\nclass TypeCheckingSuite(val base: String, override val recurse: Boolean = false)\n    extends ExprOperationAcceptanceSuite(Expr.Util.typeCheck(_))\n    with ResolvingInput\nclass AlphaNormalizationSuite(val base: String) extends ExprOperationAcceptanceSuite(_.alphaNormalize) with ParsingInput\nclass NormalizationSuite(val base: String, override val recurse: Boolean = false)\n    extends ExprOperationAcceptanceSuite(_.normalize)\n    with CachedResolvingInput\nclass NormalizationUSuite(val base: String) extends ExprOperationAcceptanceSuite(_.normalize) with ParsingInput\n\nclass HashingSuite(val base: String, override val recurse: Boolean = false)\n    extends SuccessSuite[Expr, String]\n    with ResolvingInput {\n  def makeExpectedFilename(input: String): String = input.dropRight(7) + \"B.hash\"\n\n  def transform(input: Expr): String = input.normalize.alphaNormalize.hash\n  def loadExpected(input: Array[Byte]): String = new String(input).trim.drop(7)\n  def compare(result: String, expected: String): Boolean = result == expected\n}\n\nclass ParsingSuite(val base: String) extends SuccessSuite[Expr, Array[Byte]] with ParsingInput {\n  def makeExpectedFilename(input: String): String = input.dropRight(7) + \"B.dhallb\"\n\n  def transform(input: Expr): Array[Byte] = input.getEncodedBytes\n  def loadExpected(input: Array[Byte]): Array[Byte] = input\n  def compare(result: Array[Byte], expected: Array[Byte]): Boolean = result.sameElements(expected)\n}\n\nclass BinaryDecodingSuite(val base: String) extends SuccessSuite[Expr, Expr] with ParsingInput {\n  def makeExpectedFilename(input: String): String = input.dropRight(8) + \"B.dhall\"\n\n  override def isInputFileName(fileName: String): Boolean = fileName.endsWith(\"A.dhallb\")\n\n  override def parseInput(path: String, input: String): Expr =\n    decode(readBytes(Paths.get(path)))\n\n  def transform(input: Expr): Expr = input\n  def loadExpected(input: Array[Byte]): Expr = DhallParser.parse(new String(input))\n  def compare(result: Expr, expected: Expr): Boolean = result.sameStructure(expected) && result.equivalent(expected)\n}\n"
  },
  {
    "path": "tests/src/main/scala/org/dhallj/tests/acceptance/AcceptanceSuite.scala",
    "content": "package org.dhallj.tests.acceptance\n\nimport java.nio.file.{Files, Path, Paths}\n\nimport munit.{FunSuite, Ignore, Slow}\n\nimport scala.collection.JavaConverters._\n\ntrait AcceptanceSuite extends FunSuite {\n  def prefix: String = \"./dhall-lang/tests\"\n\n  def base: String\n  def recurse: Boolean = false\n\n  def isInputFileName(fileName: String): Boolean = fileName.endsWith(\"A.dhall\")\n  def makeName(inputFileName: String): String = inputFileName.dropRight(7)\n\n  /**\n   * Test names to ignore.\n   */\n  def ignored: String => Boolean = Set.empty\n\n  /**\n   * Names of tests that are slow.\n   */\n  def slow: Set[String] = Set.empty\n\n  private def basePath: Path = Paths.get(s\"$prefix/$base\")\n\n  /**\n   * Returns a list of name-path pairs.\n   */\n  def testInputs: List[(String, Path)] = (\n    if (this.recurse) Files.walk(basePath) else Files.list(basePath)\n  ).iterator.asScala\n    .map(path => (basePath.relativize(path).toString, path))\n    .flatMap { case (name, path) =>\n      if (isInputFileName(name)) {\n        Some((makeName(name), path))\n      } else None\n    }\n    .toList\n    .sortBy(_._2)\n\n  final override def munitTests(): Seq[Test] =\n    super\n      .munitTests()\n      .map(test => if (ignored(test.name)) test.tag(Ignore) else if (slow(test.name)) test.tag(Slow) else test)\n\n  final protected def readString(path: Path): String =\n    new String(readBytes(path))\n\n  final protected def readBytes(path: Path): Array[Byte] =\n    Files.readAllBytes(path)\n}\n"
  },
  {
    "path": "tests/src/main/scala/org/dhallj/tests/acceptance/ImportResolutionSuite.scala",
    "content": "package org.dhallj.tests.acceptance\n\nimport java.nio.file.{Files, Paths}\n\nimport cats.effect.IO\nimport cats.effect.unsafe.IORuntime\n\nimport org.dhallj.core.Expr\nimport org.dhallj.imports.{ImportCache, Resolver}\nimport org.dhallj.parser.DhallParser\n\nimport org.http4s.client._\nimport org.http4s.blaze.client._\n\nimport scala.concurrent.ExecutionContext.global\nimport scala.io.Source\n\nclass ImportResolutionSuite(val base: String)\n    extends ExprOperationAcceptanceSuite(identity)\n    with CachedResolvingInput\n    with ImportResolutionHelpers {\n\n  setEnv(\"DHALL_TEST_VAR\", \"6 * 7\") //Yes, this is SUPER hacky but the JVM doesn't really support setting env vars\n\n  override def parseInput(path: String, input: String): Expr = {\n    val p = Paths.get(path)\n    val parsed = DhallParser.parse(readString(p))\n\n    if (parsed.isResolved) parsed\n    else {\n      implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global\n      val cache = initializeCache\n      BlazeClientBuilder[IO](global).resource\n        .use { client =>\n          implicit val c: Client[IO] = client\n          Resolver.resolveRelativeTo[IO](cache, new ImportCache.NoopImportCache[IO])(p.getParent)(parsed)\n        }\n        .unsafeRunSync()\n    }\n  }\n}\n\n// TODO: revisit this.\nclass ImportResolutionFailureSuite(val base: String) extends AcceptanceSuite with ImportResolutionHelpers {\n  override def isInputFileName(fileName: String): Boolean = fileName.endsWith(\".dhall\")\n  override def makeName(inputFileName: String): String = inputFileName.dropRight(6)\n\n  testInputs\n    .map { case (name, path) =>\n      (name, path, readBytes(path))\n    }\n    .foreach { case (name, path, input) =>\n      test(name) {\n        intercept[RuntimeException](parseInput(path.toString, new String(input)))\n      }\n    }\n\n  setEnv(\"DHALL_TEST_VAR\", \"6 * 7\") //Yes, this is SUPER hacky but the JVM doesn't really support setting env vars\n\n  def parseInput(path: String, input: String): Expr = {\n    val p = Paths.get(path)\n    val parsed = DhallParser.parse(readString(p))\n\n    if (parsed.isResolved) parsed\n    else {\n      implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global\n      val cache = initializeCache\n      BlazeClientBuilder[IO](global).resource\n        .use { client =>\n          implicit val c: Client[IO] = client\n          Resolver.resolveRelativeTo[IO](cache, new ImportCache.NoopImportCache[IO])(p.getParent)(parsed)\n        }\n        .unsafeRunSync()\n    }\n  }\n}\n\ntrait ImportResolutionHelpers {\n  protected def initializeCache: ImportCache[IO] = {\n    implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global\n    val dir = Files.createTempDirectory(\"dhallj\")\n    val cache = ImportCache[IO](dir).unsafeRunSync().get\n    Source\n      .fromResource(\"tests/import/cache/dhall\")\n      .getLines()\n      .foreach { p =>\n        val content = Files.readAllBytes(Paths.get(s\"dhall-lang/tests/import/cache/dhall/$p\"))\n        Files.write(dir.resolve(p), content)\n      }\n    cache\n  }\n\n  protected def setEnv(key: String, value: String): Unit = {\n    val field = System.getenv().getClass.getDeclaredField(\"m\")\n    field.setAccessible(true)\n    val map = field.get(System.getenv()).asInstanceOf[java.util.Map[java.lang.String, java.lang.String]]\n    map.put(key, value)\n  }\n}\n"
  },
  {
    "path": "tests/src/test/resources/learndhall.dhall",
    "content": "\n-- Single-line comment\n\n{- Multi-line comment\n\n   Unicode is fine 🙂\n\n   This file is a valid Dhall expression that evaluates to a large record\n   collecting the results of each step.\n\n   You can view the results by interpreting the file:\n\n       $ dhall --file learndhall.dhall\n\n   {- Comments can be nested -}\n-}\n\nlet greeting = \"Hello, world!\"\n\nlet fruits = \"🍋🍓🍍🍉🍌\"\n\nlet interpolation = \"Enjoy some delicious fruit: ${fruits}\"\n\nlet multilineText {- Inline comments work, too -} =\n        ''\n        Leading whitespace is stripped from multi-line text literals.\n\n        That means you can freely indent or dedent a text literal without\n        changing the result.\n\n            Relative indentation within the literal is still preserved.\n\n        Other than that, the text literal is preserved verbatim, similar to a\n        \"literal\" YAML multiline string.\n        ''\n\nlet bool = True\n\n-- Type annotations on bindings are optional, but helpful, so we'll use them\nlet annotation : Bool = True\n\nlet renderedBool : Text = if bool then \"True\" else \"False\"\n\n-- Natural numbers are non-negative and are unsigned\nlet naturalNumber : Natural = 42\n\n-- Integers may be negative, but require an explicit sign, even if positive\nlet positiveInteger : Integer = +1\n\nlet negativeInteger : Integer = -12\n\nlet pi : Double = 3.14159265359\n\n{- You can use a wider character range for identifiers (such as quotation\n   marks and whitespace) if you quote them using backticks\n-}\nlet `Avogadro's Number` : Double = 6.0221409e+23\n\nlet origin : { x : Double, y : Double } = { x = 0.0, y = 0.0 }\n\nlet somePrimes : List Natural = [ 2, 3, 5, 7, 11 ]\n\n{- A schema is the same thing as a type\n\n   Types begin with an uppercase letter by convention, but this convention is\n   not enforced\n-}\nlet Profile : Type\n        = { person :\n              { name : Text\n              , age  : Natural\n              }\n          , address :\n              { country : Text\n              , state   : Text\n              , city    : Text\n              }\n          }\n\nlet john : Profile =\n        { person =\n            { name = \"John Doe\"\n            , age  = 67\n            }\n        , address =\n            { country = \"United States\"\n            , state   = \"Pennsylvania\"\n            , city    = \"Philadelphia\"\n            }\n        }\n\nlet philadelphia : Text = john.address.city\n\n{- Enum alternatives also begin with an uppercase letter by convention.  This\n   convention is not enforced\n-}\nlet DNA : Type = < Adenine | Cytosine | Guanine | Thymine >\n\nlet dnaSequence : List DNA = [ DNA.Thymine, DNA.Guanine, DNA.Guanine ]\n\nlet compactDNASequence : List DNA =\n        let a = DNA.Adenine\n        let c = DNA.Cytosine\n        let g = DNA.Guanine\n        let t = DNA.Thymine\n        in  [ c, t, t, a, t, c, g, g, c ]\n\n-- You can transform enums by providing a record with one field per alternative\nlet theLetterG : Text =\n            merge\n            { Adenine  = \"A\"\n            , Cytosine = \"C\"\n            , Guanine  = \"G\"\n            , Thymine  = \"T\"\n            }\n            DNA.Guanine\n\nlet presentOptionalValue : Optional Natural = Some 1\n\nlet absentOptionalValue : Optional Natural = None Natural\n\nlet points : List { x : Double, y : Double } =\n        [ { x = 1.1, y = -4.2 }\n        , { x = 4.4, y = -3.0 }\n        , { x = 8.2, y = -5.5 }\n        ]\n\n{- `Natural -> List Natural` is the type of a function whose input type is a\n   `Natural` and whose output type is a `List Natural`\n\n   All functions in Dhall are anonymous functions (a.k.a. \"lambdas\"),\n   which you can optionally give a name\n\n   For example, the following function is equivalent to this Python code:\n\n       lambda n : [ n, n + 1 ]\n\n   ... and this JavaScript code:\n\n       function (n) { return [ n, n + 1 ]; }\n-}\nlet exampleFunction : Natural -> List Natural =\n        \\(n : Natural) -> [ n, n + 1 ]\n\n-- Dhall also supports Unicode syntax, but this tutorial will stick to ASCII\nlet unicodeFunction : Natural → List Natural =\n        λ(n : Natural) → [ n, n + 1 ]\n\n-- You don't need to parenthesize function arguments\nlet exampleFunctionApplication : List Natural =\n        exampleFunction 2\n\nlet functionOfMultipleArguments : Natural -> Natural -> List Natural =\n        \\(x : Natural) -> \\(y : Natural) -> [ x, y ]\n\nlet functionAppliedToMultipleArguments : List Natural =\n        functionOfMultipleArguments 2 3\n\n{- Same as `exampleFunction` except we gave the function's input type a\n   name: \"n\"\n-}\nlet namedArgumentType : forall (n : Natural) -> List Natural =\n        \\(n : Natural) -> [ n, n + 1 ]\n\n{- If you name a function's input type, you can use that name later within the\n   same type\n\n   This lets you write a function that works for more than one type of input\n   (a.k.a. a \"polymorphic\" function)\n-}\nlet duplicate : forall (a : Type) -> a -> List a =\n        \\(a : Type) -> \\(x : a) -> [ x, x ] \n\nlet duplicatedNumber : List Natural =\n        duplicate Natural 2\n\nlet duplicatedBool : List Bool =\n        duplicate Bool False\n\n{- The language also has some built-in polymorphic functions, such as:\n\n       List/head : forall (a : Type) -> List a -> Optional a\n-}\nlet firstPrime : Optional Natural = List/head Natural somePrimes\n\nlet functionOfARecord : { x : Natural, y : Natural } -> List Natural =\n        \\(args : { x : Natural, y : Natural }) -> [ args.x, args.y ]\n\nlet functionAppliedToARecord : List Natural =\n        functionOfARecord { x = 2, y = 5 }\n\n{- All type conversions are explicit\n\n   `Natural/show` is a built-in function of the following type:\n\n       Natural/show : Natural -> Text\n\n   ... that converts `Natural` numbers to their `Text` representation\n-}\nlet typeConversion : Natural -> Text =\n        \\(age : Natural) -> \"I am ${Natural/show age} years old!\"\n\n-- A \"template\" is the same thing as a function whose output type is `Text`\nlet mitLicense : { year : Natural, copyrightHolder : Text } -> Text =\n        \\(args : { year : Natural, copyrightHolder : Text }) ->\n''\nCopyright ${Natural/show args.year} ${args.copyrightHolder}\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of \nthis software and associated documentation files (the \"Software\"), to deal in \nthe Software without restriction, including without limitation the rights to \nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies \nof the Software, and to permit persons to whom the Software is furnished to do \nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all \ncopies 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 THE \nSOFTWARE.\n''\n\n-- Template instantiation is the same thing as function application\nlet templatedLicense : Text =\n        mitLicense { year = 2019, copyrightHolder = \"Jane Smith\" }\n\n{- You can import expressions by URL\n\n   Also, like Bash, you can import code from your local filesystem (not shown)\n\n   Security-conscious users can pin remotely-imported expressions by adding a\n   semantic integrity check.  The interpreter rejects any attempt to tamper with\n   an expression pinned in this way.  However, behavior-preserving refactors\n   of imported content will not perturb the hash.\n\n   Imported expressions pinned in this way are also locally cached in a\n   content-addressable store (typically underneath `~/.cache/dhall`)\n-}\n{-let Natural/sum : List Natural -> Natural =\n      https://prelude.dhall-lang.org/Natural/sum\n      sha256:33f7f4c3aff62e5ecf4848f964363133452d420dcde045784518fb59fa970037-}\n\nlet twentyEight : Natural = Natural/sum somePrimes\n\n-- A \"package\" is the same thing as a (possibly nested) record that you can import\n--let Prelude = https://prelude.dhall-lang.org/package.dhall\n\nlet false : Bool = Prelude.Bool.not True\n\n-- You can import the raw contents of a file by adding `as Text` to an import\n--let sourceCode : Text = https://prelude.dhall-lang.org/Bool/not as Text\n\n-- You can import environment variables, too:\n--let presentWorkingDirectory = env:PWD as Text\n\n-- You can provide a fallback expression if an import fails\n--let home : Optional Text = Some env:HOME ? None Text\n\n-- Fallback expressions can contain alternative imports of their own\n{-let possiblyCustomPrelude =\n        env:DHALL_PRELUDE\n      ? https://prelude.dhall-lang.org/package.dhall-}\n\n{- Tie everything together by auto-generating configurations for 10 build users\n   using the `generate` function:\n\n       Prelude.List.generate\n           : Natural -> forall (a : Type) -> (Natural -> a) -> List a\n-}\nlet buildUsers =\n        let makeUser = \\(user : Text) ->\n              let home       = \"/home/${user}\"\n              let privateKey = \"${home}/.ssh/id_ed25519\"\n              let publicKey  = \"${privateKey}.pub\"\n              in  { home = home\n                  , privateKey = privateKey\n                  , publicKey = publicKey\n                  }\n\n        let buildUser =\n                \\(index : Natural) -> makeUser \"build${Natural/show index}\"\n\n        let Config =\n              { home : Text\n              , privateKey : Text\n              , publicKey : Text\n              }\n\n        in  Prelude.List.generate 10 Config buildUser\n\n-- Present all of the results in a final record\nin  { greeting = greeting\n    , fruits = fruits\n    , interpolation = interpolation\n    , multilineText = multilineText\n    , bool = bool\n    , annotation = annotation\n    , renderedBool = renderedBool\n    , naturalNumber = naturalNumber\n    , positiveInteger = positiveInteger\n    , negativeInteger = negativeInteger\n    , pi = pi\n    , `Avogadro's Number` = `Avogadro's Number`\n    , origin = origin\n    , somePrimes = somePrimes\n    , john = john\n    , philadelphia = philadelphia\n    , dnaSequence = dnaSequence\n    , compactDNASequence = compactDNASequence\n    , theLetterG = theLetterG\n    , presentOptionalValue = presentOptionalValue\n    , absentOptionalValue = absentOptionalValue\n    , points = points\n    , exampleFunction = exampleFunction\n    , unicodeFunction = unicodeFunction\n    , exampleFunctionApplication = exampleFunctionApplication\n    , functionOfMultipleArguments = functionOfMultipleArguments\n    , functionAppliedToMultipleArguments = functionAppliedToMultipleArguments\n    , namedArgumentType = namedArgumentType\n    , duplicate = duplicate\n    , duplicatedNumber = duplicatedNumber\n    , duplicatedBool = duplicatedBool\n    , firstPrime = firstPrime\n    , functionOfARecord = functionOfARecord\n    , functionAppliedToARecord = functionAppliedToARecord\n    , typeConversion = typeConversion\n    , mitLicense = mitLicense\n    , templatedLicense = templatedLicense\n    , twentyEight = twentyEight\n    , false = false\n    , sourceCode = sourceCode\n    , presentWorkingDirectory = presentWorkingDirectory\n    , home = home\n    , buildUsers = buildUsers\n    }\n\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/BinaryDecodingTests.scala",
    "content": "package org.dhallj.tests\n\nimport java.nio.file.{Files, Paths}\n\nimport munit.FunSuite\nimport org.dhallj.core.binary.Decode.decode\nimport org.dhallj.parser.DhallParser.parse\n\nclass BinaryDecodingTests extends FunSuite {\n\n  test(\"Decode natural\") {\n    val bytes = load(\"nat.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"123\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode integer\") {\n    val bytes = load(\"int.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"-123\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode variable\") {\n    val bytes = load(\"var.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"x@1\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode anonymous variable\") {\n    val bytes = load(\"anon_var.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"_@1\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode builtin\") {\n    val bytes = load(\"builtin.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"Natural/even\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode True\") {\n    val bytes = load(\"true.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"True\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode False\") {\n    val bytes = load(\"false.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"False\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode empty list\") {\n    val bytes = load(\"empty_list.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"[] : List Natural\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode non-empty list\") {\n    val bytes = load(\"list.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"[1,2,3]\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode some\") {\n    val bytes = load(\"some.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"Some \\\"foo\\\"\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode lambda\") {\n    val bytes = load(\"lambda.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"\\\\(x: Text) -> x\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode anonymous lambda\") {\n    val bytes = load(\"anon_lambda.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"\\\\(_: Text) -> \\\"foo\\\"\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode pi\") {\n    val bytes = load(\"pi.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"forall (x: a) -> List x\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode anonymous pi\") {\n    val bytes = load(\"anon_pi.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"forall (_: a) -> List Text\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode function application\") {\n    val bytes = load(\"app.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"(\\\\(x: Text) -> x) \\\"foo\\\"\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode record type\") {\n    val bytes = load(\"record_type.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"{x: Text, y: Natural}\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode record literal\") {\n    val bytes = load(\"record_literal.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"{x = \\\"foo\\\", y = 3}\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode field access\") {\n    val bytes = load(\"field_access.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"{x: Text, y: Natural}.x\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode record projection\") {\n    val bytes = load(\"record_projection.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"{x: Text, y: Natural, z: Bool}.{x,y}\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode record projection by type\") {\n    val bytes = load(\"record_type_projection.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"{x = 1, y = 2, z = \\\"foo\\\"}.({x : Natural, y : Natural})\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode union\") {\n    val bytes = load(\"union.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"<Local : Text | Remote : Text | Missing>\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode merge\") {\n    val bytes = load(\"merge.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"merge { Foo = False, Bar = Natural/even } < Foo | Bar : Natural >\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode to map\") {\n    val bytes = load(\"to_map.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"toMap { bar = 2, foo = 1 }\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode assert\") {\n    val bytes = load(\"assert.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"assert : Natural/even 2 === True\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode let, 1 variable\") {\n    val bytes = load(\"let.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"let x = 1 in [x]\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode let, >1 variable\") {\n    val bytes = load(\"let.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"let x = 1 in [x]\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode type annotation\") {\n    val bytes = load(\"annotation.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"1 : Natural\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode env import\") {\n    val bytes = load(\"env_import.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"env:foo\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode local import\") {\n    val bytes = load(\"local_import.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"~/foo/bar\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode local import as text\") {\n    val bytes = load(\"local_import_text.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"../foo/bar as Text\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode local import as location\") {\n    val bytes = load(\"local_import_location.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\"/foo/bar as Location\")\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode remote import\") {\n    val bytes = load(\"remote_import.bin\")\n\n    val decoded = decode(bytes)\n    val expected = parse(\n      \"https://raw.githubusercontent.com/dhall-lang/dhall-lang/master/Prelude/package.dhall?foo=bar using { pwd = \\\"secret\\\"}\"\n    )\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode classpath import\") {\n    val bytes = parse(\"let x = classpath:/foo/bar.dhall in x\").getEncodedBytes\n\n    val decoded = decode(bytes)\n    val expected = parse(\n      \"let x = classpath:/foo/bar.dhall in x\"\n    )\n\n    assert(decoded.equivalent(expected))\n  }\n\n  test(\"Decode classpath import as text\") {\n    val bytes = parse(\"let x = classpath:/foo/bar.dhall as Text in x\").getEncodedBytes\n\n    val decoded = decode(bytes)\n    val expected = parse(\n      \"let x = classpath:/foo/bar.dhall as Text in x\"\n    )\n\n    assert(decoded.equivalent(expected))\n  }\n\n  private def load(resource: String): Array[Byte] =\n    Files.readAllBytes(Paths.get(getClass.getResource(s\"/binary/$resource\").toURI))\n\n}\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/ImportResolutionSuite.scala",
    "content": "package org.dhallj.tests\n\nimport java.nio.file.{Path, Paths}\n\nimport cats.effect.{IO, Resource}\nimport cats.effect.unsafe.implicits.global\nimport munit.FunSuite\nimport org.dhallj.core.Expr\nimport org.dhallj.imports.syntax._\nimport org.dhallj.parser.DhallParser.parse\nimport org.http4s.client._\nimport org.http4s.blaze.client._\n\nclass ImportResolutionSuite extends FunSuite {\n\n  implicit val client: Resource[IO, Client[IO]] =\n    BlazeClientBuilder[IO](scala.concurrent.ExecutionContext.global).resource\n\n  test(\"Resolve with different base directory\") {\n    //Path inside dhall-lang submodule\n    val expr = parse(\"let x = ./success/prelude/Bool/and/0B.dhall in x\")\n    val expected = parse(\"Bool\").normalize\n\n    assert(resolveRelativeTo(Paths.get(\"./dhall-lang/tests/type-inference\"))(expr) == expected)\n  }\n\n  private def resolveRelativeTo(relativeTo: Path)(e: Expr): Expr =\n    client\n      .use { c =>\n        implicit val http: Client[IO] = c\n\n        e.resolveImportsRelativeTo[IO](relativeTo).map(_.normalize)\n      }\n      .unsafeRunSync()\n\n}\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/JsonConverterSuite.scala",
    "content": "package org.dhallj.tests\n\nimport munit.FunSuite\nimport org.dhallj.core.converters.JsonConverter\nimport org.dhallj.parser.DhallParser\n\nclass JsonConverterSuite extends FunSuite() {\n  test(\"toCompactString correctly escapes text\") {\n    val expr = DhallParser.parse(\"\"\"[{mapKey = \" \\n \\$ \\\" \", mapValue = \" \\n \\$ \\\" \"}]\"\"\")\n\n    assert(clue(JsonConverter.toCompactString(expr)) == clue(\"\"\"{\" \\n $ \\\" \":\" \\n $ \\\" \"}\"\"\"))\n  }\n\n  test(\"toCompactString correctly escapes text from Text/show\") {\n    val expr = DhallParser.parse(\"\"\"Text/show \"$100 #\"\"\"\").normalize\n\n    assert(clue(JsonConverter.toCompactString(expr)) == clue(\"\"\"\"\\\"\\\\u0024100 #\\\"\"\"\"\"))\n  }\n\n  test(\"toCompactString correctly escapes text from toMap\") {\n    val expr = DhallParser.parse(\"\"\"toMap {` \\n \\$ \\\" ` = \" \\n \\$ \\\" \"}\"\"\").normalize\n\n    assert(clue(JsonConverter.toCompactString(expr)) == clue(\"\"\"{\" \\\\n \\\\$ \\\\\\\" \":\" \\n $ \\\" \"}\"\"\"))\n  }\n\n  test(\"toCompactString flattens toMap-formatted lists\") {\n    val expr = DhallParser.parse(\n      \"\"\"[{ mapKey = \"foo\", mapValue = 1}, {mapKey = \"bar\", mapValue = 2}]\"\"\"\n    )\n\n    assert(clue(JsonConverter.toCompactString(expr)) == \"\"\"{\"foo\":1,\"bar\":2}\"\"\")\n  }\n\n  test(\"toCompactString flattens toMap-typed empty lists\") {\n    val expr = DhallParser.parse(\n      \"\"\"[]: List { mapKey: Text, mapValue: Integer }\"\"\"\n    )\n\n    assert(clue(JsonConverter.toCompactString(expr)) == \"\"\"{}\"\"\")\n  }\n\n  test(\"toCompactString keeps last value in case of toMap-format duplicates\") {\n    val expr = DhallParser.parse(\n      \"\"\"[{ mapKey = \"foo\", mapValue = 100}, {mapKey = \"foo\", mapValue = 2 }]\"\"\"\n    )\n\n    assert(clue(JsonConverter.toCompactString(expr)) == \"\"\"{\"foo\":2}\"\"\")\n  }\n\n  test(\"toCompactString doesn't flatten near-toMap-format lists\") {\n    val expr = DhallParser.parse(\n      \"\"\"[{ mapKey = \"foo\", mapValue = 1}, {mapKey = \"bar\", other = 1, mapValue = 2}]\"\"\"\n    )\n\n    val expected = \"\"\"[{\"mapKey\":\"foo\",\"mapValue\":1},{\"mapKey\":\"bar\",\"other\":1,\"mapValue\":2}]\"\"\"\n\n    assert(clue(JsonConverter.toCompactString(expr)) == clue(expected))\n  }\n}\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/MiscSuite.scala",
    "content": "package org.dhallj.tests\n\nimport java.time.Instant\nimport munit.ScalaCheckSuite\nimport org.dhallj.ast._\nimport org.dhallj.core.binary.Decode\nimport org.dhallj.core.Expr\nimport org.dhallj.parser.DhallParser\nimport org.scalacheck.{Arbitrary, Gen, Prop}\n\nclass MiscSuite extends ScalaCheckSuite {\n  case class AsciiPrintableString(value: String)\n\n  implicit val arbitraryAsciiPrintableString: Arbitrary[AsciiPrintableString] =\n    Arbitrary(Gen.alphaNumStr.map(AsciiPrintableString(_)))\n\n  def checkParse(name: String, input: String, expected: Expr)(implicit loc: munit.Location): Unit =\n    test(name)(assert(clue(DhallParser.parse(input)).equivalent(clue(expected))))\n\n  def checkBetaNormalization(name: String, input: String, expected: Expr)(implicit loc: munit.Location): Unit =\n    test(name)(assert(clue(DhallParser.parse(input).normalize).equivalent(clue(expected))))\n\n  def parsesTo(input: String, expected: Expr): Boolean = DhallParser.parse(input).equivalent(expected)\n\n  test(\"getFirstDiff should work for classpath imports\") {\n    assert(\n      Option(Expr.Util.getFirstDiff(DhallParser.parse(\"classpath:/foo\"), DhallParser.parse(\"classpath:/bar\"))).nonEmpty\n    )\n  }\n\n  property(\"doubles\")(Prop.forAll((value: Double) => parsesTo(value.toString, DoubleLiteral(value))))\n  property(\"naturals\")(Prop.forAll((value: BigInt) => parsesTo(value.abs.toString, NaturalLiteral(value.abs).get)))\n  property(\"strings\")(\n    Prop.forAll((value: AsciiPrintableString) => parsesTo(s\"\"\"\"${value.value}\"\"\"\", TextLiteral(value.value)))\n  )\n\n  property(\"round-trip instants\")(\n    Prop.forAll { (value: Instant) =>\n      val asString = value.toString\n      val parts = asString.split(\"-\")\n\n      // We need a reasonable four-digit year.\n      val cleaned = (\n        if (parts(0).isEmpty) {\n          // If it's negative we just make something up.\n          \"2021\" + \"-\" + parts.drop(2).mkString(\"-\")\n        } else if (parts(0).size != 4) {\n          // If it's not four digits we just make something up.\n          \"1999\" + \"-\" + parts.drop(1).mkString(\"-\")\n        } else {\n          asString\n        }\n        // The ScalaCheck instance produces instants that can't be parsed.\n      ).replaceAll(\"-02-29\", \"-02-28\")\n\n      val expected = Instant.parse(cleaned)\n\n      val result = Decode.decode(DhallParser.parse(cleaned).getEncodedBytes).toString\n\n      // Keep it low-tech.\n      val resultString = result.substring(8, 18) + \"T\" + result.substring(46).takeWhile(_ != '}') + \"Z\"\n\n      Instant.parse(resultString) == expected\n    }\n  )\n}\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/PreludeSuite.scala",
    "content": "package org.dhallj.tests\n\nimport java.nio.file.Paths\nimport munit.{FunSuite, Ignore, Slow, TestOptions}\nimport org.dhallj.imports.mini.Resolver\nimport org.dhallj.parser.DhallParser\nimport scala.io.Source\n\nclass PreludeSuite extends FunSuite() {\n  val haskellDhallIsAvailable = HaskellDhall.isAvailable()\n\n  val preludeFiles = Source.fromResource(s\"Prelude\").getLines().toList.sorted.flatMap {\n    case \"Monoid\"        => Nil\n    case \"Monoid.dhall\"  => List(\"Prelude/Monoid.dhall\")\n    case \"README.md\"     => Nil\n    case \"package.dhall\" => List(\"Prelude/package.dhall\")\n    case other =>\n      Source.fromResource(s\"Prelude/$other\").getLines().toList.sorted.map { case file =>\n        s\"Prelude/$other/$file\"\n      }\n  }\n\n  def slow: Set[String] = Set(\n    \"Prelude/JSON/render\",\n    \"Prelude/JSON/renderAs\",\n    \"Prelude/JSON/renderYAML\",\n    \"Prelude/JSON/package.dhall\",\n    \"Prelude/package.dhall\"\n  )\n\n  def checkHash(path: String)(implicit loc: munit.Location): Unit = {\n    val content = Source.fromResource(path).getLines().mkString(\"\\n\")\n    val parsed = DhallParser.parse(content)\n\n    val resolved = Resolver.resolveFromResources(parsed, false, Paths.get(path), this.getClass.getClassLoader)\n\n    val name = s\"$path hash matches dhall hash\"\n\n    val testOptions: TestOptions = if (haskellDhallIsAvailable) {\n      if (slow(path)) name.tag(Slow) else name\n    } else name.tag(Ignore)\n\n    lazy val expected = HaskellDhall.hashFromPath(s\"dhall-lang/$path\")\n\n    test(testOptions)(assert(resolved.normalize.alphaNormalize.hash == clue(expected)))\n  }\n\n  preludeFiles.foreach(checkHash)\n}\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/ToStringSuite.scala",
    "content": "package org.dhallj.tests\n\nimport munit.{Ignore, ScalaCheckSuite, Slow}\nimport org.dhallj.core.{Expr, Operator}\nimport org.dhallj.parser.DhallParser\nimport org.dhallj.testing.WellTypedExpr\nimport org.dhallj.testing.instances._\nimport org.scalacheck.Prop\nimport scala.util.Try\n\nclass ToStringSuite extends ScalaCheckSuite() {\n  property(\"toString produces parseable code given well-typed values\") {\n    Prop.forAll((expr: WellTypedExpr) => DhallParser.parse(clue(expr.value.toString)) == expr.value)\n  }\n\n  property(\"toString produces parseable code\") {\n    Prop.forAll((expr: Expr) => DhallParser.parse(clue(expr.toString)) == expr)\n  }\n\n  property(\"toString produces parseable code for sequence of operators\") {\n    Prop.forAll { (ops: Vector[Operator]) =>\n      val x = Expr.makeIdentifier(\"x\")\n      val expr1 = ops.take(16).foldLeft(x) { case (acc, op) => Expr.makeOperatorApplication(op, x, acc) }\n      val expr2 = ops.take(16).foldLeft(x) { case (acc, op) => Expr.makeOperatorApplication(op, acc, x) }\n      DhallParser.parse(clue(expr1.toString)) == expr1 && DhallParser.parse(clue(expr2.toString)) == expr2\n    }\n  }\n\n  // TODO: make this pass (e.g. seed rBdMB22PVU38DRrcK3rrh1kEBDitFj8dL1tbCloBmgM=)\n  property(\"toString doesn't introduce unnecessary parentheses\".tag(Ignore)) {\n    Prop.forAll { (expr: Expr) =>\n      val asString = expr.toString\n\n      removeParentheses(asString).forall { smaller =>\n        !Try(DhallParser.parse(smaller)).toOption.exists(_ == expr)\n      }\n    }\n  }\n\n  test(\"Unnormalized Prelude should round-trip through toString\".tag(Slow)) {\n    import org.dhallj.syntax._\n\n    val Right(prelude) = \"./dhall-lang/Prelude/package.dhall\".parseExpr.flatMap(_.resolve)\n    val Right(fromToString) = prelude.toString.parseExpr\n\n    assert(prelude.hash.sameElements(fromToString.hash))\n    assert(prelude.diff(fromToString).isEmpty)\n  }\n\n  private def closingIndex(input: String, startIndex: Int): Int = {\n    var i = startIndex + 1\n    var depth = 1\n\n    while (i < input.length && depth > 0) {\n      if (input.charAt(i) == ')') {\n        depth -= 1\n      } else if (input.charAt(i) == '(') {\n        depth += 1\n      }\n      i += 1\n    }\n\n    i - 1\n  }\n\n  // Assumes valid nesting\n  private def removeParentheses(input: String, first: Int = 0): List[String] = {\n    val nextIndex = input.indexOf(\"(\", first)\n\n    if (nextIndex < 0) {\n      Nil\n    } else {\n      val end = closingIndex(input, nextIndex)\n      val next = input.take(nextIndex) + input.substring(nextIndex + 1, end) + input.substring(end + 1)\n\n      next :: removeParentheses(input, nextIndex + 1)\n    }\n  }\n}\n"
  },
  {
    "path": "tests/src/test/scala/org/dhallj/tests/acceptance/AcceptanceSuites.scala",
    "content": "package org.dhallj.tests.acceptance\n\nclass NormalizationSimpleSuite extends NormalizationUSuite(\"normalization/success/simple\")\nclass NormalizationRegressionSuite extends NormalizationSuite(\"normalization/success/regression\")\nclass NormalizationUnitSuite extends NormalizationUSuite(\"normalization/success/unit\")\nclass NormalizationSimplificationsSuite extends NormalizationSuite(\"normalization/success/simplifications\")\nclass NormalizationOtherSuite extends NormalizationSuite(\"normalization/success\")\nclass NormalizationHaskellTutorialSuite extends NormalizationSuite(\"normalization/success/haskell-tutorial\", true)\n\nclass HashingSimpleSuite extends HashingSuite(\"semantic-hash/success/simple\")\nclass HashingSimplificationsSuite extends HashingSuite(\"semantic-hash/success/simplifications\")\nclass HashingOtherSuite extends HashingSuite(\"semantic-hash/success\")\nclass HashingHaskellTutorialSuite extends HashingSuite(\"semantic-hash/success/haskell-tutorial\", true)\nclass HashingPreludeSuite extends HashingSuite(\"semantic-hash/success/prelude\", true)\n\nclass AlphaNormalizationUnitSuite extends AlphaNormalizationSuite(\"alpha-normalization/success/unit\")\nclass AlphaNormalizationRegressionSuite extends AlphaNormalizationSuite(\"alpha-normalization/success/regression\")\n\nclass TypeCheckingSimpleSuite extends ParsingTypeCheckingSuite(\"type-inference/success/simple\")\nclass TypeCheckingUnitSuite extends ParsingTypeCheckingSuite(\"type-inference/success/unit\")\nclass TypeCheckingRegressionSuite extends TypeCheckingSuite(\"type-inference/success/regression\")\nclass TypeCheckingOtherSuite extends TypeCheckingSuite(\"type-inference/success\") {\n  override def slow = Set(\"prelude\")\n  // Depends on http://csrng.net/, which is rate-limited (and also currently entirely down).\n  // Temporary workaround awaiting dhall-lang#1198 (prelude only).\n  override def ignored = Set(\"CacheImports\", \"CacheImportsCanonicalize\", \"prelude\")\n}\nclass TypeCheckingFailureUnitSuite extends TypeCheckingFailureSuite(\"type-inference/failure/unit\")\nclass TypeCheckingPreludeSuite extends TypeCheckingSuite(\"type-inference/success/prelude\", true) {\n  // Temporary workaround awaiting dhall-lang#1198.\n  override def ignored = _.startsWith(\"Monoid/\")\n}\n\nclass ParsingUnitSuite extends ParsingSuite(\"parser/success/unit\")\nclass ParsingTextSuite extends ParsingSuite(\"parser/success/text\")\n\nclass ParsingTimeSuite extends ParsingSuite(\"parser/success/time\")\nclass ParsingOtherSuite extends ParsingSuite(\"parser/success\")\n\nclass ParsingFailureUnitSuite extends ParsingFailureSuite(\"parser/failure/unit\") {\n  // TODO: Fix these WithPrecedenceN failures; these are known bugs.\n  override def ignored = Set(\"WithPrecedence2\", \"WithPrecedence3\")\n}\nclass ParsingFailureSpacingSuite extends ParsingFailureSuite(\"parser/failure/spacing\")\n\nclass ParsingFailureTimeSuite extends ParsingFailureSuite(\"parser/failure/time\")\nclass ParsingFailureOtherSuite extends ParsingFailureSuite(\"parser/failure\") {\n  // We ignore \"nonUtf8\" because by the time we see a string in Java any non-UTF-8 characters have\n  // been replaced. See `DhallParserSuite` for a non-ignored test that covers the same ground.\n  override def ignored = Set(\"nonUtf8\")\n}\n\nclass BinaryDecodingUnitSuite extends BinaryDecodingSuite(\"binary-decode/success/unit\")\nclass BinaryDecodingImportsUnitSuite extends BinaryDecodingSuite(\"binary-decode/success/unit/imports\")\nclass BinaryDecodingFailureUnitSuite extends BinaryDecodingFailureSuite(\"binary-decode/failure/unit\")\n\nclass ImportResolutionSuccessSuite extends ImportResolutionSuite(\"import/success\")\nclass ImportResolutionSuccessUnitSuite extends ImportResolutionSuite(\"import/success/unit\") {\n  // TODO: fix this bug\n  override def ignored = Set(\"DontCacheIfHash\")\n}\nclass ImportResolutionSuccessUnitAsLocationSuite extends ImportResolutionSuite(\"import/success/unit/asLocation\")\nclass ImportResolutionFailureUnitSuite extends ImportResolutionFailureSuite(\"import/failure/unit\")\nclass ImportResolutionFailureOtherSuite extends ImportResolutionFailureSuite(\"import/failure\")\n"
  },
  {
    "path": "version.sbt",
    "content": "ThisBuild / version := \"0.10.0-M2\"\n"
  }
]