[
  {
    "path": ".gitattributes",
    "content": "stable/* linguist-vendored\nexample/* linguist-vendored\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nelm-stuff/\nnode_modules/\nelchemy.js\noutput.ex\nexample/elm.js\n.#*\n.elchemy*\n*.orig\nelixir-stuff/\nelchemy_ex/lib/*\n*un~\nelchemy-*.ez\n_build/\ndocs/\nexample/\nstable/\n_book/\n.elixir_ls/\n.vscode/\ntest_project/\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"elchemy-core\"]\n\tpath = elchemy-core\n\turl = https://github.com/wende/elchemy-core.git\n"
  },
  {
    "path": ".npmrc",
    "content": "tag-version-prefix = \"\""
  },
  {
    "path": ".tool-versions",
    "content": "elm 0.18.0\nelixir 1.7.4\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: elixir\nelixir:\n  - 1.5.0\n  - 1.6.4\n  - 1.7.0\n  - 1.7.1\n  - 1.7.3\notp_release:\n  - 20.0\n  - 21.0\nmatrix:\n  exclude:\n  # Elixir 1.5.0 doesn't work with OTP 21\n  - elixir: 1.5.0\n    otp_release: 21.0\n  # Elixir 1.6.4 doesn't work with OTP 21\n  - elixir: 1.6.4\n    otp_release: 21.0\nos:\n  - linux\ncache:\n  directories:\n    - test/elm-stuff/build-artifacts\n    - sysconfcpus\n\nbefore_install:\n  - if [ ${TRAVIS_OS_NAME} == \"osx\" ];\n    then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh;\n    fi\n  - echo -e \"Host github.com\\n\\tStrictHostKeyChecking no\\n\" >> ~/.ssh/config\n  - | # epic build time improvement - see https://github.com/elm-lang/elm-compiler/issues/1473#issuecomment-245704142\n    if [ ! -d sysconfcpus/bin ];\n    then\n      git clone https://github.com/obmarg/libsysconfcpus.git;\n      cd libsysconfcpus;\n      ./configure --prefix=$TRAVIS_BUILD_DIR/sysconfcpus;\n      make && make install;\n      cd ..;\n    fi\n\ninstall:\n  - nvm install 6.11.2\n  - nvm use 6.11.2\n  - node --version\n  - npm --version\n  - npm install -g elm@0.18.0\n  - mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-old\n  - printf '%s\\n\\n' '#!/bin/bash' 'echo \"Running elm-make with sysconfcpus -n 2\"' '$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-old \"$@\"' > $(npm config get prefix)/bin/elm-make\n  - chmod +x $(npm config get prefix)/bin/elm-make\n  - npm install\n  - elm package install --yes\n  - cd elchemy-core/\n  - mix local.rebar --force # for Elixir 1.3.0 and up\n  - mix local.hex --force\n  - mix deps.get\n  - cd ../\n  - make compile\n  - make compile-std\n\nafter_failure:\n  - find elchemy-core/lib | xargs cat\n\nscript:\n  - make test-all\n\nnotifications:\n  email: false\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at krzysztof.wende@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "ISSUE_TEMPLATE",
    "content": "### Check first\nIf anything doesn't work, try\n```\nnpm install -g elchemy\nelchemy clean\nelchemy init\nmix test\n```\n\nTo experiment with the latest Elchemy version of the parser online go to\nhttps://wende.github.io/elchemy/stable/\n\n### Template: \nAdd:\n\n## Example:\n```elm\n\n```\n->\n```elixir\n\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Krzysztof Wende\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in 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"
  },
  {
    "path": "Main.elm",
    "content": "port module Main exposing (main)\n\nimport Html exposing (..)\nimport Html\nimport Elchemy.Compiler as Compiler\nimport Markdown\n\n\ntype Msg\n    = Replace String\n    | String\n\n\nview : String -> Html Msg\nview model =\n    Markdown.toHtml [] <| \"```elixir\\n\" ++ (Compiler.tree model) ++ \"\\n```\"\n\n\ninit : String -> ( String, Cmd Msg )\ninit v =\n    ( v, Cmd.none )\n\n\nmain : Program String String Msg\nmain =\n    Html.programWithFlags\n        { init = init\n        , update = update\n        , view = view\n        , subscriptions =\n            (\\_ ->\n                Sub.batch\n                    [ updateInput Replace\n                    ]\n            )\n        }\n\n\nupdate : Msg -> String -> ( String, Cmd Msg )\nupdate action model =\n    case action of\n        Replace m ->\n            ( m, Cmd.none )\n\n        String ->\n            ( \"\", Cmd.none )\n\n\nport updateInput : (String -> msg) -> Sub msg\n"
  },
  {
    "path": "Makefile",
    "content": "dev:\n\tpkill -f http-server &\n\techo \"Make sure to install http-server with npm i -g http-server\"\n\telm-make Main.elm --output=example/elm.js --debug\n\t(http-server ./example/ -p 8081 -c-1 &) && open \"http://127.0.0.1:8081\"\n\nrelease:\n\telm-make Main.elm --output=example/elm.js\n\tmkdir -p docs/stable\n\tcp -r example/ docs/stable/\n\ncompile:\n\telm-make Main.elm --yes --output compiled.js\n\tsed 's/var Elm = {}/&; \\\n\trequire(\".\\/elchemy_node.js\").execute(_user$$project$$Elchemy_Compiler$$tree, _user$$project$$Elchemy_Compiler$$fullTree, _user$$project$$Elchemy_Compiler$$treeAndCommons)/' compiled.js > elchemy.js\n\trm compiled.js\n\ncompile-watch:\n\tfind . -name \"*.elm\" | grep -v \"elm-stuff\" | grep -v .# | entr make compile\n\ntest:\n\t./node_modules/.bin/elm-test\n\ntest-all:\n\tmake test\n\tmake test-std\n\tmake compile-elixir # Change to compile-elixir-and-test when let..in fixed completely\n\tmake test-project\n\ntest-project:\n\trm -rf test_project\n\tmix new test_project\n\tcd test_project ; \\\n\t\t(yes | ../elchemy init) ;\\\n\t\t../elchemy compile elm lib  ;\\\n\t\tcp -r ../elchemy-core/lib lib/elm-deps ;\\\n\t\tcp -r ../elchemy-core/elm lib/elm-deps-elixir-files ;\\\n\t\tmix test\n\ntest-std:\n\tcd elchemy-core/ && mix test\n\ncompile-std:\n\tcd elchemy-core && rm -rf .elchemy\n\tmake compile-std-incremental\n\ncompile-std-incremental:\n\tmake compile\n\tcd elchemy-core && ../elchemy compile elm lib\n\ncompile-std-watch:\n\tfind elchemy-core -name \"*.elm\" | grep -v \".#\" | grep -v \"elm-stuff\" | entr make compile-std\n\ncompile-std-tests-watch:\n\tfind elchemy-core \\( -name \"*.elm\" -or -name '*.ex*' \\) | grep -v \"elchemy.ex\" | grep -v \".#\" | grep -v \"elm-stuff\" | entr bash -c \"make compile && make compile-std && make test-std\"\n\ncompile-incremental-std-tests-watch:\n\tfind elchemy-core \\( -name \"*.elm\" -or -name '*.ex*' \\) | grep -v \"elchemy.ex\" | grep -v \".#\" | grep -v \"elm-stuff\" | entr bash -c \"make compile && make compile-std-incremental && make test-std\"\n\ntests-watch:\n\tfind . -name \"*.elm\" | grep -v \".#\" | grep -v \"elm-stuff\" | entr ./node_modules/.bin/elm-test\n\ninstall-sysconf:\n\tgit clone \"https://github.com/obmarg/libsysconfcpus.git\"\n\tcd libsysconfcpus && ./configure && make && make install\n\tcd .. && rm -rf libsysconfcpus\n\ncompile-elixir:\n\tmake compile\n\trm -rf elchemy_ex/elm-deps\n\trm -rf elchemy_ex/.elchemy\n\tcd elchemy_ex && ../elchemy compile ../src lib\n\ncompile-elixir-and-run:\n\tmake compile-elixir\n\tcd elchemy_ex && mix compile\n\ncompile-elixir-and-test:\n\tmake compile-elixir\n\tcd elchemy_ex && mix test\n\nbuild-docs:\n\tcd ../elchemy-page && git checkout master && git pull && elm install && yarn && yarn build\n\trm -rf docs/*\n\tcp -r ../elchemy-page/dist/* docs/\n"
  },
  {
    "path": "README.md",
    "content": "\n<p align=\"center\">\n<img src=\"https://github.com/wende/elchemy/blob/master/logo.png?raw=true\" width=\"250\" height=\"250\">\n</p>\n<p align=\"center\">\n  <a href=\"https://join.slack.com/t/elchemy-lang/shared_invite/enQtNjMzMDI0NzM3MzQ3LWVmZDZkMzY3OWZkMzJlOGIzZjMzMjcwMDgzNDFlZDYzY2NiYzE0ZjdhOTRmMmMyMjRiOTUzNjhhNWQ1M2VlMGY\">\n    <img src=\"https://img.shields.io/badge/chat-on%20slack-blueviolet.svg\">\n  </a>\n  <a href=\"http://elchemy.neontree.pl\">\n    <img src=\"https://img.shields.io/badge/try%20now-online-yellow.svg\">\n  </a>\n  <a href=\"https://wende.gitbooks.io/elchemy/content/\">\n    <img src=\"https://img.shields.io/badge/read-docs-informational.svg\">\n  </a>\n  <a href=\"https://medium.com/@krzysztof.wende/elmchemy-write-type-safe-elixir-code-with-elms-syntax-part-1-introduction-8968b76d721d\">\n    <img src=\"https://img.shields.io/badge/getting-started-green.svg\">\n  </a>\n  <a href=\"https://travis-ci.org/wende/elchemy\">\n    <img src=\"https://travis-ci.org/wende/elchemy.svg?branch=master\">\n  </a>\n \n</p>\n\n#### Quick install\n\n```shell\nnpm install -g elchemy\n```\n\n\n# What is it?\n\nElchemy lets you write simple, fast and quality type safe code while leveraging both the Elm's safety and Elixir's ecosystem\n\n\n### In case of any questions about the project feel free to submit them in Issues with Q&A label\n\n\n# Features\n\n- **Type inference:** Powerful type inference means you rarely have to annotate types. Everything gets checked for you by the compiler\n- **Easy and type-safe interop**: You can call Elixir/Erlang without any extra boiler-plate. All the calls you make are checked in terms of type-safety as thoroughly as possible based on Elixir's typespecs.\n- **All the best of Elm and Elixir**: Elchemy inherits what's best in Elm - type safety, inference and extreme expressiveness, but also what's best in Elixir - Doc-tests, tooling and obviously the entire BEAM platform.\n- **Nearly no runtime errors** - Elchemy's type system **eliminates almost all runtime errors**. With a shrinking set of edge cases, your entire Elchemy codebase is safe. Elixir parts of the codebase are the only ones to be a suspect in cases of runtime errors happening.\n- **Beautiful and fully readable output** - The produced code is idiomatic, performant and can be easily read and analyzed without taking a single look at the original source.\n\n\n# Maturity of the project\n\n- Parser - **99%** of Elm's syntax (see [elm-ast](https://github.com/Bogdanp/elm-ast/issues))\n- Compiler - **90%** (Sophisticated incremental compilation. \n  No support for Windows yet though ([#287](https://github.com/wende/elchemy/issues/287)) and also big reliance on unix tools ([#288](https://github.com/wende/elchemy/issues/288))\n- Elchemy-core - **95%** ( Everything covered except side effects and JSON Decoders) \n- Interop with Elixir - **90%** - Purity tests ([#162](https://github.com/wende/elchemy/issues/162)) and handling of macro-heavy libraries ([#276](https://github.com/wende/elchemy/issues/276)) to go \n- Ideology - **70%** - We've got a pretty solid idea of where Elchemy is going \n- Documentation - **80%** - There are two tutorials and a complete Gitbook documentation. Few entrance level tutorials though, this project tries to change it. \n- Elchemy-effects - **20%** - You can't and shouldn't write anything with side-effects in Elchemy yet. We're working on finding the best solution for effects that would fit both Elm's and Elixir's community (see [#297](https://github.com/wende/elchemy/issues/297) for more info)\n- Elchemy-core for Erlang VM - **5%** - Everything for os related tasks like filesystem, OTP goodies etc are yet to be done\n- Elchemy type checker - **20%** - Self-hosted elchemy type inference algorithm, written by @wende and inspired by @Bogdanp.\n\n# Usage\n\n### Prerequisites\n\n- [elixir@1.4.0-1.6.x](https://elixir-lang.org/install.html)\n- [node@5+](https://nodejs.org/en/)\n- [elm-lang@0.18.0](https://guide.elm-lang.org/install.html) (`npm install -g elm@0.18.0`)\n- [elm-github-install@0.1.2](https://github.com/gdotdesign/elm-github-install) - Compiler will install it automatically for you, if you don't have it yet.\n\n\n### Installation in an existing Elixir project\n\n\nInstall `elchemy` globally with:\n\n```shell\nnpm install -g elchemy\n```\n\n\nThen, in the root directory of your project do:\n\n```shell\nelchemy init\n```\n\nAnd follow the instructions.\n\n`elchemy` will find all `*.elm` files specified in `elchemy_path` and compile it into corresponding `*.ex` files in `lib` directory.\n\nYou can override output directory specifying `elixirc_paths`.\n\n\n### Installation as a standalone\n\n```shell\nnpm install -g elchemy\n```\n\nUsage\n\n```\nelchemy compile source_dir output_dir\n```\n\n### Recommended editors setup\n\n- [Atom](https://atom.io/) with [elixir-language](https://atom.io/packages/language-elixir) and [atom-elixir](https://github.com/msaraiva/atom-elixir) or [elixir-ide](https://atom.io/packages/ide-elixir) for Elixir; and [language-elm](https://atom.io/packages/language-elm) + [elmjutsu](https://atom.io/packages/elmjutsu) for Elchemy.\n- [Visual Studio Code](https://code.visualstudio.com/) with [vscode-elixir](https://marketplace.visualstudio.com/items?itemName=mjmcloug.vscode-elixir), [vscode-elixir-ls](https://github.com/JakeBecker/vscode-elixir-ls) and [vscode-elm](https://github.com/elm-tooling/elm-language-client-vscode)\n\n\n### Build from source\n\n```\ngit clone https://github.com/wende/elchemy.git\ncd elchemy\nmake compile\n./elchemy compile source_dir output_dir\n```\n\nand\n\n```\nmake dev\n```\n\nIn order to launch and test the web demo.\n\n\n## Troubleshooting\n\nIf something doesn't work, try \n\n\n```\nnpm install -g elchemy\nelchemy clean\nelchemy init\nmix test\n```\n\nfirst\n\n\n# FAQ\n\n## Why *would* I want to use that?\n\n- You like types\n- But even more you prefer compile-time errors over run-time error\n- You prefer `add b c = b + c` over `defp add(a, b), do: b + c`\n- You like curry\n- You think failing fast is cool, but not as cool as not failing at all\n\n\n## Why *wouldn't* I want to use that?\n\n- Your project relies on die-hard battle tested libraries, and you despise any versions starting with 0\n- You're afraid that when you learn what Monad is your mustache will grow, and eyesight weaken\n\n\n## Can I use it in already existing Elixir project?\n\nYou can, but nice and dandy compile tools are still on their way\n\n\n## Will my employer notice I'm having an affair with Elchemy?\n\nThe output files of Elchemy treat the code readability as a first class citizen. The code is meant to be properly indented, the comments aren't omitted, and the code is optimized as hard as it can ( f.i case clauses reduce to function overloads)\n\n\n## When will Elchemy become 1.0.0?\n\nOnce it's done, so as it is supposed to be in the so called semantic versioning. :innocent:\n\n\n## Can I contribute?\n\nDefinitely. Yes. Please do. :two_hearts:\n\n\n## How are types represented?\n\nYou're a nosy one, aren't you? :smile: Elchemy represents all type constructors as snake cased atoms, and all type applications as tuples. Which means that `MyType 42 \"Forty two\" Error` in Elchemy equals to `{:my_type, 42, \"Forty Two\", :error}` in Elixir.\n\n\n## Can I use already existing Elm libraries with Elchemy?\n\nAs long as they don't use any Native modules, Ports or Elm runtime they can be safely imported and used\n\n\n## Can I use already existing Elixir libraries with Elchemy?\n\nYes. You can do an `ffi` call to any function in any module. Whether it's Elixir module, Erlang module, or even a macro you can include it in your code. Ffi calls are a treated specially in Elchemy, and they get generated test to analyze the types based on @specs, so that you don't compromise type safety for using Elixir code. \nIn order to increase readability it's advised not to use `ffi` calls if not necessary and always document and doctest them.\n\n\n## But what about out of function macros? Like tests and `use Module`?\n\nUnfortunately you can't write any macros with `do..end` blocks yet. You can write any out of function code using an elixir inline code with:\n\n\n```elm\n{- ex\n  *code_here*\n-}\n```\n\nBut it is a last resort solution and shouldn't ever be abused.\n\n\n## Can I define an Elixir macro in Elchemy?\n\nSo you want to write an Elm-like code, that will manipulate Elixir code, which generates an Elixir code that manipulates Elixir code? How about no?\n\n\n## Do I need to have Elm installed to compile my `.elm` files with Elchemy?\n\nElchemy uses Elm to typecheck your program. It is possible to use it without Elm on your machine, while it's not advised.\n\n\n# Contributor credits:\n\n- Tomasz Cichociński - [@baransu](https://github.com/baransu)\n- Colin Bankier - [@colinbankier](https://github.com/colinbankier)\n- Nathaniel Knight - [@neganp](https://github.com/neganp)\n\n# Inspiration:\n\n- [Elm](https://github.com/elm/compiler) by Evan Czaplicki - [@evancz](https://github.com/evancz)\n- [Elixir](https://github.com/elixir-lang/elixir) by José Valim - [@josevalim](https://github.com/josevalim)\n- [Elm-AST](https://github.com/bogdanp/elm-ast) by Bogdan Popa - [@bogdanp](https://github.com/bogdanp) \n\n\n# Contributing Guide\n\n- Everyone is welcome to contribute :hugs:\n- Refer to https://bogdanp.github.io/elm-ast/example/ to have better understanding of parsed tokens.\n- Refer to https://wende.github.io/elchemy/stable/ to know the latest development version of the parser\n- For project management we use ZenHub. You can see the Kanban board, card estimates and all the reports by installing a browser extension here: [Opera/Chrome](https://chrome.google.com/webstore/detail/zenhub-for-github/ogcgkffhplmphkaahpmffcafajaocjbd), [Firefox](zenhub.com)\n\n\n## Targeted values:\n\n- Fully readable and indented elixir code generated from compilation\n- Seamless and stress less interop with existing Elixir code, preferably with magically working type safety\n- Full integration with entire elm syntax for editors and compilers magic\n\n\n"
  },
  {
    "path": "book.json",
    "content": "{\n    \"root\" : \"./roadmap\"\n}\n"
  },
  {
    "path": "bump.sh",
    "content": " #!/bin/bash\n\n set -e\n\n if [ -z \"$1\" ]; then\n    echo 'usage ./bump.sh [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]'\n    exit 0\nfi\nif git diff-index --quiet HEAD --; then\n    CHANGELOG=`git changelog -x --tag VER`\n    npm version $1\n    SEMVER='[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9]*-*[0-9]*'\n    VER=`npm ls | grep -o elchemy@$SEMVER | grep -o $SEMVER`\n    CHANGELOG=${CHANGELOG/VER/$VER}\n    echo \"$CHANGELOG\"\n\n    make compile-std\n\n    cd elchemy-core\n\n    CORE_BRANCH=`git branch | grep \\* | cut -d ' ' -f2`\n\n    sed -i \"\" \"s/$SEMVER/$VER/g\" mix.exs\n\n    git pull origin $CORE_BRANCH\n\n    git commit -am \"Release $VER\"\n    git tag $VER\n\n    if ! [[ $* == *-n* ]]; then\n      git push origin $CORE_BRANCH $VER\n    fi\n\n    cd ..\n\n    ELCHEMY_BRANCH=`git branch | grep \\* | cut -d ' ' -f2`\n\n    sed -i \"\" \"s/$SEMVER/$VER/g\" mix.exs\n    sed -i \"\" \"s/elchemy-core\\\": \\\"0.0.0 <= v < $SEMVER/elchemy-core\\\": \\\"0.0.0 <= v < $VER/g\" ./templates/elm-package.json\n\n    rm -f elchemy-*.ez\n    mix archive.build\n    mix archive.install \"elchemy-$VER.ez\" --force\n\n    git pull origin $ELCHEMY_BRANCH\n    sed -i \"\" \"s/$SEMVER/$VER/g\" src/Elchemy/Compiler.elm\n    make compile\n    make build-docs\n    make release\n    git add docs/ -f\n\n    sed -i \"\" \"s/version=\\\"$SEMVER\\\"/version=\\\"$VER\\\"/g\" ./elchemy\n    sed -i \"\" \"s/name\\\": \\\"elchemy\\\"/name\\\": \\\"elmchemy\\\"/g\" package.json\n    if ! [[ $* == *-n* ]]; then\n      npm publish\n    fi\n    sed -i \"\" \"s/name\\\": \\\"elmchemy\\\"/name\\\": \\\"elchemy\\\"/g\" package.json\n\n    if ! [[ $* == *-n* ]]; then\n      npm publish\n    fi\n\n    git tag -d \"$VER\"\n    git commit -am \"$CHANGELOG\"\n    git tag $VER\n    if ! [[ $* == *-n* ]]; then\n      git push origin $ELCHEMY_BRANCH $VER\n      hub release create -p -a \"elchemy-$VER.ez\" $VER\n    fi\nelse\n    echo \"Git directory must be clean\"\n    exit 1\nfi\n"
  },
  {
    "path": "elchemy",
    "content": "#!/bin/bash\n\n\nversion=\"0.8.8\"\n\nif ! $(elm -v 2> /dev/null | grep 0.18 > /dev/null ); then\n    echo \"Elchemy requires elm 0.18. Install it and make sure it's available system-wide.\"\n    echo \"For 0.19 support visit https://github.com/wende/elchemy/issues/348\"\n    exit 1\nfi\n\nset -e\n\nVERBOSE=false\nif [[ $* == *--verbose* ]]; then\n  VERBOSE=true\nfi\n\nfunction create_file {\n    local file=$1\n    if [[ ${file} == *\"elm-stuff/packages\"* ]]; then\n        file=${file/elm-stuff\\/packages/elm-deps}\n    fi\n    mkdir -p `dirname $file`\n    echo \"\" > $file\n    echo \"$file\"\n}\n\nSOURCE=\"${BASH_SOURCE[0]}\"\nwhile [ -h \"$SOURCE\" ]; do # resolve $SOURCE until the file is no longer a symlink\n    DIR=\"$( cd -P \"$( dirname \"$SOURCE\" )\" && pwd )\"\n    SOURCE=\"$(readlink \"$SOURCE\")\"\n    [[ $SOURCE != /* ]] && SOURCE=\"$DIR/$SOURCE\" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located\ndone\nSOURCE_DIR=\"$( cd -P \"$( dirname \"$SOURCE\" )\" && pwd )\"\n\ncase \"$1\" in\n    version)\n        echo \"Elchemy $version\"\n        ;;\n    clean)\n      rm -rf ./elm-deps\n      rm -rf ./elm-stuff\n      rm -rf ~/.elm-install/github.com/\n      find . | grep \"\\.elchemy.ex\" | xargs rm -f\n      rm -rf .elchemy\n      ;;\n    new)\n        mix new $2\n        cd $2\n        $SOURCE_DIR/elchemy init\n        ;;\n    init)\n        if [ -a ./mix.exs ]\n        then\n            cp $SOURCE_DIR/templates/elchemy.exs ./.elchemy.exs\n            mix archive.install \"https://github.com/wende/elchemy/releases/download/$version/elchemy-$version.ez\"\n            mkdir -p elm\n            cp $SOURCE_DIR/templates/elm-package.json ./\n            cp $SOURCE_DIR/templates/Hello.elm ./elm/\n            if [ -d ./test ]; then\n                cp $SOURCE_DIR/templates/elchemy_test.exs ./test/\n            fi\n            printf  \"Elchemy $version initialised. Make sure to add:\\n\\n\\t|> elem(Code.eval_file(\\\".elchemy.exs\\\"), 0).init\\n\\nto your mix.exs file as the last line of the project() function.\\nThis pipes the project keyword list to the elchemy init function to configure some additional values.\\n\\nThen run mix test to check if everything went fine\\n\"\n            printf \"\\nelm-deps\" >> .gitignore\n            printf \"\\nelm-stuff\" >> .gitignore\n            printf \"\\node_modules\" >> .gitignore\n            printf \"\\.elchemy\" >> .gitignore\n        else\n            printf  \"ERROR: No elixir project found. Make sure to run init in a project\"\n        fi\n    ;;\n    compile)\n        # Create ./.elchemy if doesn't exist\n        mkdir -p \".elchemy\"\n        MTIME=\"$(cat \".elchemy/mtime\" 2> /dev/null || echo \"1995-04-10 23:35:02\")\"\n        echo \"\" > .elchemy/output\n        if [ ! -d ./elm-deps ] || [[ !  $(find ./elm-package.json -newermt \"$MTIME\") == \"\" ]]; then\n            if ! hash elm-github-install 2>/dev/null; then\n                echo \"No elm-github-install found. Installing...\"\n                npm i -g elm-github-install@1.6.1\n            fi\n            echo \"-- Downloading Elchemy deps --\"\n            elm-install\n        fi\n        # Copy all elixir files that are inside packages\n        echo \"-- Copying Elixir native files --\"\n        for f in `{ find -L elm-stuff/packages -name \"*.ex*\" | grep -v \"\\.elchemy\\.ex\" ;}`\n        do\n          if [ $VERBOSE = true ]; then\n            echo \"FOUND $f\"\n          fi\n          file=\"${file/^elm\\//lib\\//}\"\n          file=$(create_file $f)\n          if [ $VERBOSE = true ]; then\n             echo \"TO $file\"\n           fi\n          cp $f $file\n        done\n        i=0\n        echo \"-- Compiling Elm files --\"\n        # Find all elm files inside packages and compile them\n        for f in `{ find $2 -name \"*.elm\" -newermt \"$MTIME\" | grep -v \"elm-stuff\" | grep -v \"#.\" ; find -L elm-stuff/packages -name \"*.elm\" -newermt \"$MTIME\" | grep -v \"/tests/\" | grep -v \"/example/\" ;}`\n        do\n            if [[ ${f} == *\"elm-lang\"* ]] || [[ ${f} == *\"Elchemy.elm\"* ]]; then\n                continue\n            fi\n            echo \"----------\"\n            echo \"Type Checking $f\"\n            echo \">>>>$f\" >> .elchemy/output\n            # We don't need to typecheck deps again\n            if [[ ${f} != *\"elm-stuff\"* ]] && ! [[ $* == *--unsafe* ]]; then\n                (echo n | elm-make $f --output .elchemy/output_tmp.js) || { echo 'Type Check failed' ; exit 1; }\n                rm .elchemy/output_tmp.js\n            fi\n            i=$((i+1))\n            echo \"#$i\"\n            cat $f >> .elchemy/output\n        done\n        echo \"-- Linking files --\"\n        node --max_old_space_size=8192 $SOURCE_DIR/elchemy.js .elchemy/output .elchemy/elixir_output .elchemy/cache.json\n        current_file=\"\"\n        while IFS= read -r line; do\n            if [[ $line =~ \">>>>\" ]]; then\n                current_file=\"${line/\\/\\///}\"\n                current_file=\"${current_file/>>>>/}\"\n                echo \"Linking: $current_file\"\n                current_file=\"${current_file/$2\\//$3/}\"\n                current_file=\"${current_file%%.elm}.elchemy.ex\"\n                current_file=$(echo ${current_file} | perl -pe 's/([a-z0-9])([A-Z])/$1_\\L$2/g')\n                current_file=$(create_file $current_file)\n                echo \"To: $current_file\"\n                else\n                if [ \"$current_file\" != \"\" ]; then\n                    printf '%s\\n' \"$line\" >> \"$current_file\"\n                fi\n            fi\n        done < .elchemy/elixir_output\n        #rm .elchemy/elixir_output\n        #rm .elchemy/output\n        echo $(date +\"%Y-%m-%d %H:%M:%S\") > .elchemy/mtime\n        ;;\n    *)\n        echo $\"Usage: $0 <COMMAND> [<ARGS>]\"\n        cat <<EOF\n\nAvailable commands include:\n\n    new <PROJECT_NAME>\n        Start a new project\n\n    init\n        Add Elchemy to an existing project\n\n    compile [INPUT_DIR] [OUTPUT_DIR] [--unsafe]\n        Compile Elchemy source code\n\n    clean\n        Remove temporary files\n\n    version\n        Print Elchmey's version number number and exit\n\nEOF\n        exit 1\n\nesac\n"
  },
  {
    "path": "elchemy_ex/.gitignore",
    "content": "# The directory Mix will write compiled artifacts to.\n/_build/\n\n# If you run \"mix test --cover\", coverage assets end up here.\n/cover/\n\n# The directory Mix downloads your dependencies sources to.\n/deps/\n\n# Where 3rd-party dependencies like ExDoc output generated docs.\n/doc/\n\n# Ignore .fetch files in case you like to edit your project deps locally.\n/.fetch\n\n# If the VM crashes, it generates a dump, let's ignore it too.\nerl_crash.dump\n\n# Also ignore archive artifacts (built via \"mix archive.build\").\n*.ez\n\nelm-deps\nelm-stuff\n"
  },
  {
    "path": "elchemy_ex/README.md",
    "content": "# ElchemyEx\n\n**TODO: Add description**\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed\nby adding `elchemy_ex` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:elchemy_ex, \"~> 0.1.0\"}\n  ]\nend\n```\n\nDocumentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)\nand published on [HexDocs](https://hexdocs.pm). Once published, the docs can\nbe found at [https://hexdocs.pm/elchemy_ex](https://hexdocs.pm/elchemy_ex).\n\n"
  },
  {
    "path": "elchemy_ex/config/config.exs",
    "content": "# This file is responsible for configuring your application\n# and its dependencies with the aid of the Mix.Config module.\nuse Mix.Config\n\n# This configuration is loaded before any dependency and is restricted\n# to this project. If another project depends on this project, this\n# file won't be loaded nor affect the parent project. For this reason,\n# if you want to provide default values for your application for\n# 3rd-party users, it should be done in your \"mix.exs\" file.\n\n# You can configure your application as:\n#\n#     config :elchemy_ex, key: :value\n#\n# and access this configuration in your application as:\n#\n#     Application.get_env(:elchemy_ex, :key)\n#\n# You can also configure a 3rd-party app:\n#\n#     config :logger, level: :info\n#\n\n# It is also possible to import configuration files, relative to this\n# directory. For example, you can emulate configuration per environment\n# by uncommenting the line below and defining dev.exs, test.exs and such.\n# Configuration from the imported file will override the ones defined\n# here (which is why it is important to import them last).\n#\n#     import_config \"#{Mix.env}.exs\"\n"
  },
  {
    "path": "elchemy_ex/elm/Hello.elm",
    "content": "module Hello exposing (..)\n\n\n{-| Prints \"world!\"\n\n    hello == \"world!\"\n-}\nhello : String\nhello =\n    \"world!\"\n"
  },
  {
    "path": "elchemy_ex/elm-package.json",
    "content": "{\n    \"version\": \"1.0.0\",\n    \"summary\": \"helpful summary of your project, less than 80 characters\",\n    \"repository\": \"https://github.com/user/project.git\",\n    \"license\": \"BSD3\",\n    \"source-directories\": [\n        \"../src\"\n    ],\n    \"exposed-modules\": [\n        \"Compiler\"\n    ],\n    \"dependencies\": {\n        \"wende/elchemy-core\" : \"0.0.0 <= v <= 1.0.0\",\n        \"elm-lang/core\": \"5.1.1 <= v < 6.0.0\",\n        \"elm-lang/html\": \"2.0.0 <= v < 3.0.0\",\n        \"evancz/elm-markdown\": \"3.0.2 <= v < 4.0.0\",\n        \"Bogdanp/elm-ast\": \"8.0.9 <= v < 9.0.0\",\n        \"elm-community/list-extra\": \"6.0.0 <= v < 7.0.0\"\n    },\n    \"dependency-sources\": {\n        \"wende/elchemy-core\" : \"../elchemy-core/\"\n    },\n    \"elm-version\": \"0.18.0 <= v < 0.19.0\"\n}\n"
  },
  {
    "path": "elchemy_ex/mix.exs",
    "content": "defmodule ElchemyEx.Mixfile do\n  use Mix.Project\n\n  def project do\n    [\n      app: :elchemy_ex,\n      version: \"0.1.0\",\n      elixir: \"~> 1.4\",\n      # Commented out until release\n      # compilers: [:elchemy, :yecc, :leex, :erlang, :elixir, :app],\n      elixirc_paths: [\"lib\", \"elm-deps\"],\n      elchemy_path: \"../src\",\n      start_permanent: Mix.env == :prod,\n      deps: deps()\n    ]\n  end\n\n  # Run \"mix help compile.app\" to learn about applications.\n  def application do\n    [\n      extra_applications: [:logger]\n    ]\n  end\n\n  # Run \"mix help deps\" to learn about dependencies.\n  defp deps do\n    [\n      # {:dep_from_hexpm, \"~> 0.3.0\"},\n      # {:dep_from_git, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.1.0\"},\n    ]\n  end\nend\n"
  },
  {
    "path": "elchemy_ex/test/elchemy_ex_test.exs",
    "content": "defmodule ElchemyExTest do\n  use ExUnit.Case\n\n  test \"Parsing works\" do\n    assert Ast.parse(\"module A exposing (..)\\na = 1\") != []\n  end\nend\n"
  },
  {
    "path": "elchemy_ex/test/test_helper.exs",
    "content": "ExUnit.start()\n"
  },
  {
    "path": "elchemy_node.js",
    "content": "var path = require(\"path\")\nvar fs = require(\"fs\");\n\nvar SOURCE_DIR = process.argv[2]\nvar TARGET_DIR = process.argv[3]\nvar CACHE_PATH = process.argv[4]\n\nfunction execute(tree, fullTree, treeAndCommons) {\n  var cacheExists = CACHE_PATH && fs.existsSync(CACHE_PATH)\n\n  // If cache is provided and cache doesn't exist the compiler doesn't expect cache, and will produce cache after compilation\n  if(CACHE_PATH && !cacheExists) {\n    var compiledSource = fs.readFileSync(SOURCE_DIR).toString();\n    var compiledOutput = treeAndCommons(compiledSource);\n    var compiledCode = compiledOutput._0\n    var compiledCache = JSON.stringify(compiledOutput._1)\n    fs.writeFileSync(TARGET_DIR, compiledCode);\n    fs.writeFileSync(CACHE_PATH, compiledCache);\n  }\n  // If cache ISN'T provided the compiler DOESN'T expect cache.\n  else if(!CACHE_PATH){\n  \tvar compiledSource = fs.readFileSync(SOURCE_DIR).toString();\n    var compiledCode = tree(compiledSource);\n  \tfs.writeFileSync(TARGET_DIR, compiledCode);\n  }\n  // If found it will use the cached ExContext.commons and compile target using it\n  else {\n    var cachedCommons = JSON.parse(fs.readFileSync(CACHE_PATH).toString())\n    var compiledSource = fs.readFileSync(SOURCE_DIR).toString();\n    var compiledOutput = fullTree(cachedCommons)(compiledSource);\n    var compiledCode = compiledOutput._0\n    fs.writeFileSync(TARGET_DIR, compiledCode);\n  }\n}\n\n\nmodule.exports = {\n  execute: execute\n}\n"
  },
  {
    "path": "elm-package.json",
    "content": "{\n    \"version\": \"1.0.0\",\n    \"summary\": \"helpful summary of your project, less than 80 characters\",\n    \"repository\": \"https://github.com/user/project.git\",\n    \"license\": \"BSD3\",\n    \"source-directories\": [\n        \".\",\n        \"./src\"\n    ],\n    \"exposed-modules\": [\n        \"Elchemy.Compiler\"\n    ],\n    \"dependencies\": {\n        \"elm-lang/core\": \"5.1.1 <= v < 6.0.0\",\n        \"elm-lang/html\": \"2.0.0 <= v < 3.0.0\",\n        \"evancz/elm-markdown\": \"3.0.2 <= v < 4.0.0\",\n        \"Bogdanp/elm-ast\": \"8.0.0 <= v < 10.0.0\",\n        \"elm-community/list-extra\": \"6.0.0 <= v < 7.0.0\"\n    },\n    \"elm-version\": \"0.18.0 <= v < 0.19.0\"\n}\n"
  },
  {
    "path": "elmchemy",
    "content": "#!/bin/bash\n\necho \"!!! DEPRECATION NOTICE !!!\"\necho \"elmchemy name is deprecated. Use elchemy (without an m) instead\"\necho \"!!! DEPRECATION NOTICE !!!\"\n\nSOURCE=\"${BASH_SOURCE[0]}\"\nwhile [ -h \"$SOURCE\" ]; do # resolve $SOURCE until the file is no longer a symlink\n    DIR=\"$( cd -P \"$( dirname \"$SOURCE\" )\" && pwd )\"\n    SOURCE=\"$(readlink \"$SOURCE\")\"\n    [[ $SOURCE != /* ]] && SOURCE=\"$DIR/$SOURCE\" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located\ndone\nSOURCE_DIR=\"$( cd -P \"$( dirname \"$SOURCE\" )\" && pwd )\"\n\n$SOURCE_DIR/elchemy \"$@\"\n"
  },
  {
    "path": "lib/mix/mix.exs",
    "content": "defmodule Elchemy.Mixfile do\n  use Mix.Project\n\n  def project do\n    [app: :elchemy,\n     name: \"Elchemy Compiler\",\n     description: \"Mix compiler wrapper around Elchemy project\",\n     version: \"0.4.25\",\n     elixir: \"~> 1.4\",\n     description: \"\",\n     package: package(),\n     build_embedded: Mix.env == :prod,\n     start_permanent: Mix.env == :prod,\n     elixirc_paths: [\"elm\", \"lib\"],\n     elchemy_path: \"elm\",\n     deps: deps()]\n  end\n  defp package do\n    # These are the default files included in the package\n    [\n      name: :elchemy,\n      files: [\"lib\", \"priv\", \"mix.exs\", \"README*\", \"readme*\", \"LICENSE*\", \"license*\"],\n      maintainers: [\"Krzysztof Wende\"],\n      licenses: [\"Apache 2.0\"],\n      links: %{\"GitHub\" => \"https://github.com/wende/elchemy\"}\n    ]\n  end\n  # Configuration for the OTP application\n  #\n  # Type \"mix help compile.app\" for more information\n  def application do\n    # Specify extra applications you'll use from Erlang/Elixir\n    [extra_applications: [:logger]]\n  end\n\n  # Dependencies can be Hex packages:\n  #\n  #   {:my_dep, \"~> 0.4.25\"}\n  #\n  # Or git/path repositories:\n  #\n  #   {:my_dep, git: \"https://github.com/elixir-lang/my_dep.git\", tag: \"0.4.25\"}\n  #\n  # Type \"mix help deps\" for more examples and options\n  defp deps do\n    []\n  end\nend\n"
  },
  {
    "path": "lib/mix/tasks/compile.elchemy.ex",
    "content": "defmodule Mix.Tasks.Compile.Elchemy do\n  use Mix.Task\n\n  def run(_args) do\n    project = Mix.Project.config\n    src = project[:elchemy_path]\n    dests = project[:elixirc_paths] || [\"lib\"]\n    elchemy_executable = project[:elchemy_executable] || \"elchemy\"\n    version = System.version\n\n    # Crash if elchemy not found globally\n    unless 0 == Mix.shell.cmd(\"which #{elchemy_executable}\") do\n      Mix.raise \"Elchemy not found under #{elchemy_executable}. You might need to run `npm install elchemy -g`\"\n    end\n\n    # Crash if elchemy not found globally\n    unless dests, do: IO.warn \"No 'elixirc_paths' setting found\"\n    if src && dests do\n      [dest | _] = dests\n      unless 0 == Mix.shell.cmd(\"#{elchemy_executable} compile #{src} #{dest}\") do\n        Mix.raise \"Elchemy failed the compilation with an error\\n\"\n      end\n    end\n\n    # Force project to be reloaded and deps compiled after elm-deps created.\n    IO.puts \"-- Recompiling dependencies for elchemy --\"\n    if project = Mix.Project.pop() do\n      %{name: name, file: file} = project\n      Mix.Project.push(name, file)\n    end\n    Mix.Task.run \"deps.get\"\n    Mix.Task.run \"deps.compile\"\n    IO.puts \"-- Elchemy compilation complete --\\n\"\n\n    if Regex.match?(~r/1.7.[0-9]+$/, version), do: IO.warn \"Elchemy's functionality is limited in Elixit 1.7. To support the full experience please use different Elixir version\"\n  end\nend\n"
  },
  {
    "path": "mix.exs",
    "content": "defmodule Elchemy.Mixfile do\n  use Mix.Project\n\n  def project do\n    [app: :elchemy,\n     name: \"Elchemy Compiler\",\n     description: \"Mix compiler wrapper around Elchemy project\",\n     version: \"0.8.8\",\n     elixir: \"~> 1.4\",\n     description: \"\",\n     package: package(),\n     build_embedded: Mix.env == :prod,\n     start_permanent: Mix.env == :prod,\n     elixirc_paths: [\"elm\", \"lib\", \"elm-deps\"],\n     elchemy_path: \"elm\",\n     deps: deps()]\n  end\n  defp package do\n    # These are the default files included in the package\n    [\n      name: :elchemy,\n      files: [\"lib\", \"priv\", \"mix.exs\", \"README*\", \"readme*\", \"LICENSE*\", \"license*\"],\n      maintainers: [\"Krzysztof Wende\"],\n      licenses: [\"Apache 2.0\"],\n      links: %{\"GitHub\" => \"https://github.com/wende/elchemy\"}\n    ]\n  end\n  # Configuration for the OTP application\n  #\n  # Type \"mix help compile.app\" for more information\n  def application do\n    # Specify extra applications you'll use from Erlang/Elixir\n    [extra_applications: [:logger]]\n  end\n\n  defp deps do\n    []\n  end\nend\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"elchemy\",\n  \"version\": \"0.8.8\",\n  \"description\": \"Write Elixir code using Elm-inspired syntax (elm-make compatible)\",\n  \"directories\": {\n    \"example\": \"example\",\n    \"test\": \"tests\"\n  },\n  \"files\": [\n    \"elchemy\",\n    \"elchemy.js\",\n    \"elchemy_node.js\",\n    \"templates/*\"\n  ],\n  \"bin\": {\n    \"elchemy\": \"./elchemy\"\n  },\n  \"scripts\": {\n    \"test\": \"elm-test\",\n    \"precommit\": \"lint-staged\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/wende/elchemy.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/wende/elchemy/issues\"\n  },\n  \"homepage\": \"https://github.com/wende/elchemy#readme\",\n  \"devDependencies\": {\n    \"elm-format\": \"^0.6.1-alpha\",\n    \"elm-test\": \"0.18.0\",\n    \"husky\": \"^0.13.3\",\n    \"lint-staged\": \"^3.4.1\"\n  },\n  \"lint-staged\": {\n    \"*.elm\": [\n      \"node_modules/.bin/elm-format --yes\",\n      \"git add\"\n    ]\n  }\n}\n"
  },
  {
    "path": "roadmap/BASIC_TYPES.md",
    "content": "# Basic types\n\n\nBecause Elm and Elixir share a lot of common basic types, there is no need to redefine all of them for Elchemy. For simplicity and interoperability some of the standard types translate directly to each other.\n\nHere is a table of all standard types used in the Elchemy environment and their Elixir equivalents:\n\n|  Elchemy | Elixir |\n|  --- |  --- |\n| `a` | `any()`\n| `comparable` | `term()`\n| `Int` | `integer()`\n| `Float` | `number()`\n| `number` | `number()`\n| `Bool` | `boolean()`\n| `Char` | `integer()`\n| `String` | `String.t()`\n| `List x` | `list()`\n| `(1, 2)` | `{1, 2}`\n| `Maybe Int` | `{integer()}` &#124; `nil`\n| `Just x` | `{x}`\n| `Nothing` | `nil`\n| `Result x y` | `{:ok, y}` &#124; `{:error, x}`\n| `Ok x` | `{:ok, x}`\n| `Err x` | `{:error, x}`\n| `{x = 1, y = 1}`   | `%{x: 1, y: 1}` |\n| `Dict String Int`   |  `%{key(String.t()) => integer())}` |\n"
  },
  {
    "path": "roadmap/COMMENTS.md",
    "content": "# Comments\n\nIn Elchemy there is several types of comments.\n\n### Inline comments\n```elm\n-- My comment\n```\n\nWhich are always ignored by the compiler and won't be included in the compiled output file\n\n### Block comment\n\nSecond type of a comment is a block comment\n\n``` elm\n{- block comment -}\n```\n\nWhich are included in the output file, but can only be used as a top level construct\n\n### Doc comments\nAnother one and probably most important is a doc-comment.\n\n``` elm\n{-| Doc comment -}\n```\nDoc-comments follow these rules:\n\n1. **First doc comment in a file always compiles to a `@moduledoc`**\n2. Doc comments before types compile to `@typedoc`\n3. Doc comments before functions compile to `@doc`\n4. A doc comment with 4 space indentation and containing a `==` comparison in it will be compiled to a **one line** [doctest](https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#doctests)\n\nDoctest example:\n\n```elm\n{-| My function adds two values\n\n       myFunction 1 2 == 3\n-}\n```\n\nWould end up being\n\n```elixir\n@doc \"\"\"\n     My function adds two values\n\n        iex> my_function().(1).(2)\n        3\n \"\"\"\n```\n"
  },
  {
    "path": "roadmap/FLAGS.md",
    "content": "# Flags\n\nElchemy compiler for purposes of experimenting and stretching the boundaries accepts flags.\n\n#### DO NOT ATTEMPT TO DO THAT UNLESS YOU'RE SURE IT'S THE ONLY WAY\n\nTo pass a flag to a compiler there is a special comment syntax\n\n```\n{- flag flagname:+argument flagname2:+argument2 }\n```\n\nSo far there is 4 flag types:\n#### `notype:+TypeName`\nOmits putting the `@type` into the compiled output code  \nUsed when you need type checking inside Elchemy ecosystem, without forwarding the definition into the output code.  \nExample:\n```elm\n{- flag notype:+MyHiddenType -}\ntype MyHiddenType = Hidden a\n```\n---\n#### `nodef:+functionName`\nOmits entire function definition from the code output. The function `@spec` will still be produced.\nExample:\n```elm\n{- flag nodef:+myHiddenFunction -}\nmyHiddenFunction = 1\n```\n---\n#### `nospec:+functionName`\nOmits function spec from the code output\nExample:\n```elm\n{- flag nospec:+myHiddenFunction -}\nmyHiddenFunction : Int\n```\n---\n#### `noverify:+functionName`\nOmits function verify macro from the code output. Usable only when using for functions defined as FFI\nExample:\n```elm\n{- flag nospec:+myHiddenFunction -}\nmyHiddenFunction : Int\n```\n"
  },
  {
    "path": "roadmap/FUNCTIONS.md",
    "content": "# Function definition and currying\n\n### Function definition\nTo define a function that gets exported you **need** to declare a type for it with\n\n``` elm\nfunctionName : ArgType -> ArgType2 -> ReturnType\n```\n\nAnd a function body underneath\n\n``` elm\nfunctionName argOne argTwo = body\n```\n\nThis will output following definition:\n\n``` elixir\ncurry function_name/2\n@spec function_name(arg_type, arg_type2) :: return_type\ndef function_name(arg_one, arg_two) do\n  body\nend\n```\n\nFollowing rules apply:\n\n1. A function will use `def` or `defp` based on `exposing` clause at the top of the module\n2. The name of the function as well as its spec will always be snake_cased version of the camelCase name\n3. `curry function/arity` is a construct that makes the function redefined in a form that takes 0 arguments, and returns X times curried function (2 times in this example). Which means that from elixir our function can be called both as: `function_name(arg_one, arg_two)` or `function_name().(arg_one).(arg_two)` and it won't have any different effect\n4. `@spec` clause will always resolve types provided, to a most readable and still understandable by the elixir compiler form\n\n#### Curried definition\nBecause of the curried nature of Elm function definitions we can just make our function return functions\n\nFor example instead of writing\n\n``` elm\naddTwo : Int -> Int\naddTwo a = 2 + a\n```\n\nWe could just write\n\n``` elm\naddTwo : Int -> Int\naddTwo = (+) 2\n```\n\nIn which case Elchemy will recognize a curried return and still provide you with a 1 and 0 arity functions, not only the 0 one.\nAnd output of such a definition would look like:\n\n``` elixir\ncurry add_two/1\n@spec add_two(integer) :: integer\ndef add_two(x1) do\n   (&+/0).(2).(x1)\nend\n```\nWhich basically means that Elchemy derives function arity from the type, rathar then function body\n"
  },
  {
    "path": "roadmap/INLINING.md",
    "content": "# Inlining Elixir Code\n\n\n#### DO NOT ATTEMPT TO DO THAT UNLESS YOU'RE SURE IT'S THE ONLY WAY\n\nIn Elchemy it's possible to inline Elixir code using\n\n```elm\n{- ex\n\n## Code\ndef any_function() do\n  1\nend\n\n-}\n```\n"
  },
  {
    "path": "roadmap/INSTALLATION.md",
    "content": "# Installation\n\nYou can install Elchemy using [npm](https://www.npmjs.com/) with\n```\nnpm install -g elchemy\n```\n\nTo integrate Elchemy with your project you need to execute:\n\n```\nelchemy init\n```\n\nInside your elixir project directory.\nIf you don't have a project created, you need to first create it. It's advised to use  [Mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#our-first-project) for that.\n\nAssuming the simplest example project called `my_project` the standard path would be:\n\n```\nmix new my_project\ncd my_project\nelchemy init\n```\n\nThen open your `mix.exs` file inside project root directory. And add:\n```elixir\n|> elem(Code.eval_file(\".elchemy.exs\"), 0).init\n```\n\nAt the end of your `project/0` function definition. Like so:\n(As of OTP 21.0 and above you must also add `@compile :tuple_calls` at the top of the Mix module. It is caused by tuple calls support being removed from newer versions of Erlang)\nBefore:\n```elixir\ndefmodule MyProject.Mixfile do\n  use Mix.Project\n\n  def project do\n    [\n      app: :my_project,\n      version: \"0.1.0\",\n      elixir: \"~> 1.5\",\n      start_permanent: Mix.env == :prod,\n      deps: deps()\n    ]\n  end\n\n  # Run \"mix help compile.app\" to learn about applications.\n  def application do\n  ...\n```\nAfter:\n```elixir\ndefmodule MyProject.Mixfile do\n  use Mix.Project\n  \n  def project do\n    [\n      app: :my_project,\n      version: \"0.1.0\",\n      elixir: \"~> 1.5\",\n      start_permanent: Mix.env == :prod,\n      deps: deps()\n    ] |> elem(Code.eval_file(\".elchemy.exs\"), 0).init\n  end\n\n  # Run \"mix help compile.app\" to learn about applications.\n  def application do\n  ...\n```\n"
  },
  {
    "path": "roadmap/INTEROP.md",
    "content": "# Interop\n\n\n## Calling Elchemy\n\nTo call generated code from Elchemy you don't need anything special.  \nEach function exposed from a module can be called either in it's regular or curried form.\n\nKeep in mind that in case of functions expecting a [higher-order function\\[s\\]](https://en.wikipedia.org/wiki/Higher-order_function) in its parameters Elchemy will also do it's magic to make sure it's compatible both ways.\n\nFor instance if your function looks like that:\n```elm\napplyFunction2 : (a -> b -> c) -> a -> b -> c\napplyFunction2 f p1 p2 = f p1 p2\n```\n\nYou can call it Elixir way:  \n```elixir\napply_function2(fn a, b -> a + b end)\n```\nAs well as Elchemy (curried) way:\n```elixir\napply_function2(fn a -> fn b -> a + b end end)\n```\nAnd it will work as fine\n\n\n---\n## Calling Elixir\n\n\nTo call elixir from Elchemy you need to define a foreign function interface.\nTo do that you can use `ffi` [special syntax (?)](SPECIAL_SYNTAX.md)\n\n`ffi` requires the function to have a very specific format, which is:\n\n1. You need to make sure the type signature is adequate to the corresponding typespec of a function\n2. There should be no explicitly stated parameters (Defined as `f = ...` not `f a b c = ...`)\n3. The **only** expression inside the function should be an ffi call in a format of:\n`ffi \"Module\" \"function\"`\n\nA good example of an ffi call would be\n\n```elm\n    upcase : String -> String\n    upcase =\n        ffi \"String\" \"upcase\"\n```\nA generated code of that statement would be\n\n``` elixir\n    @spec upcase(String.t) :: String.t\n    curry upcase/1\n    verify as: String.upcase/1\n    def upcase(a1), do: String.upcase(a1)\n```\n\nWhere `verify, as:` is a type safety generator about which you can read more in [testing](TESTING.md) section.\n"
  },
  {
    "path": "roadmap/MODULES.md",
    "content": "# Module definition and imports\n\nTo define a module in Elchemy you need to use a\n\n``` elm\nmodule ModuleName exposing (..)\n```\n\nWhich would directly translate to `defmodule` block where functions/types mentioned in the `exposing` clause will automatically use `def` or `defp`\n\n## Imports\n\nThere are two types of imports in Elchemy.\n\n### Without exposing\nOne is a import without exposed functions like\n\n``` elm\nimport SomeModule\n```\nWhich would directly translate to\n\n``` elixir\nalias SomeModule\n```\n\nBecause it doesn't import any of the exposed contents, only makes sure\nthat the module is in our namespace.\n\n### With exposing\n\n``` elm\nimport SomeModule exposing (funA, TypeA, funB)\n```\nWhich outputs\n\n``` elixir\nimport SomeModule, only: [{:fun_a, 0}, {:fun_b, 0}]\n```\n\nWhich would put `SomeModule` into our namespace and also allow us to use\n`fun_a` and `fun_b` without explicitly adding a module name before them.\n"
  },
  {
    "path": "roadmap/README.md",
    "content": "# Elchemy\n\nThis page lists all of the ideas and solutions behind Elchemy to share the\nideology as well as existing and incoming solutions to problems this project faced\nor eventually will have to face\n\n# Table of contents\n## Basics\n  - [Basic Types](BASIC_TYPES.md)\n  - [Defining Types](TYPES.md)\n  - [Defining Type Aliases](TYPE_ALIASES.md)\n  - [Structures](STRUCTURES.md)\n  - [Defining Modules](MODULES.md)\n  - [Defining Functions](FUNCTIONS.md)\n  - [Comments](COMMENTS.md)\n  - [Interop (Foreign Function Interface)](INTEROP.md)\n\n## Advanced\n  - [Side Effects / TEA](SIDE_EFFECTS.md)\n  - [Unit Testing](TESTING.md)\n  - [Compiler flags](FLAGS.md)\n  - [Inlining Elixir](INLINING.md)\n\n## Tooling\n  - [Installation](./INSTALLATION.md)\n  - [Troubleshooting](TROUBLESHOOTING.md)\n\n# Introduction\n\n\nElchemy is a set of tools and frameworks, designed to provide a language and an environment\nas close to [Elm programming language](http://elm-lang.org) as possible, to build server applications\nin a DSL-like manner for Erlang VM platform, with a readable and efficient Elixir code as an output.\n\n## Features\n\nElchemy inherits many values from its parents: Elm and Elixir\n\n### Elm\n- ML like syntax maximizing expressiveness with additional readability and simplicity constraints\n- Static typing with type inference\n- Beautiful compilation errors\n- Tagged union types and type aliases with type parameters (aka generic types)\n- All functions are curried by default\n- [No typeclasses](http://www.haskellforall.com/2012/05/scrap-your-type-classes.html)\n\n### Erlang/Elixir\n- Documentation as a first class citizen\n- Doc tests\n- Battle-tested distribution system that just works\n\n### Additional\n- Foreign function calls type safety\n- Foreign function calls purity checks\n- Dependency system based on GitHub\n- Compile time code optimizations\n"
  },
  {
    "path": "roadmap/SIDE_EFFECTS.md",
    "content": "# Side Effects\n\nSide Effects are yet to come. You can read in detail about the plans for implementing them here [#297](https://github.com/wende/elchemy/issues/297)\n"
  },
  {
    "path": "roadmap/STRUCTURES.md",
    "content": "# Structs\n\nElchemy represents all the structs as maps, so a struct defined like\n\n``` elm\nhuman : { name : String\n        , age : Int\n        }\n```\nIs an equivalent of\n\n``` elixir\n@spec human :: %{name: String.t(), age: integer()}\n```\n\nAlso type aliases denoting structs can be instantiated like functions\n\n``` elm\ntype alias Human =\n     { name : String\n     , age : Int\n     }\n```\n``` elm\nHuman \"Krzysztof\" 22\n```\n\n## Struct polymorphism\nWhat's more structs can describe a map that has at least specified elements using an update syntax.\n\n``` elm\ntype alias Employee x =\n     { x\n     | salary : Int\n     }\n```\nWhich means any struct that has a field `salary` of type integer.\nThat way we can define our pseudo-inheritance and polymorphism for more advanced structures.\n\n``` elm\ntype alias Human =\n     Employee\n        { name : String\n        , age : Int }\n\nhuman : Human\n```\nWould resolve to\n\n``` elixir\n@spec human :: %{\n  salary: integer(),\n  name: String.t,\n  age: integer()\n}\n```\n\nBut be advised that using this \"polymorphic\" approach strips us from the ability to use type aliases as constructors.\n"
  },
  {
    "path": "roadmap/SUMMARY.md",
    "content": "# Summary\n\n### Documentation\n* [Table Of Contents](./README.md)\n* [Installation](./INSTALLATION.md)\n* Basics\n    * [Syntax overview](./SYNTAX.md)\n    * [Basic Types](./BASIC_TYPES.md)\n    * [Defining Types](./TYPES.md)\n    * [Defining Type Aliases](./TYPE_ALIASES.md)\n    * [Defining Structures](./STRUCTURES.md)\n    * [Defining Modules](./MODULES.md)\n    * [Defining Functions](./FUNCTIONS.md)\n    * [Comments](./COMMENTS.md)\n    * [Interop](./INTEROP.md)\n* Advanced\n    * [Side Effects / TEA](./SIDE_EFFECTS.md)\n    * [Unit Testing](./TESTING.md)\n    * [Compiler Flags](./FLAGS.md)\n    * [Inlining Elixir](./INLINING.md)\n* Tooling\n    * [Troubleshooting](./TROUBLESHOOTING.md)\n"
  },
  {
    "path": "roadmap/SYNTAX.md",
    "content": "Elchemy is a functional reactive programming language that compiles to (server-side) Elixir (Erlang VM).\nElchemy is statically typed, which means that the compiler catches most errors immediately and provides clear and understandable error messages.\n\n```elm\n-- Single line comments start with two dashes.\n{- Multiline comments can be enclosed in a block like this.\n{- They can be nested. -}\n-}\n\n{-- The Basics --}\n\n-- Arithmetic\n1 + 1 -- 2\n8 - 1 -- 7\n10 * 2 -- 20\n\n-- Every number literal without a decimal point can be either an Int or a Float.\n33 / 2 -- 16.5 with floating point division\n33 // 2 -- 16 with integer division\n\n-- Exponents\n5 ^ 2 -- 25\n\n-- Booleans\nnot True -- False\nnot False -- True\n1 == 1 -- True\n1 /= 1 -- False\n1 < 10 -- True\n\n-- Strings and characters\n\"This is a string because it uses double quotes.\"\n'a' -- characters in single quotes\n\n-- Strings can be appended.\n\"Hello \" ++ \"world!\" -- \"Hello world!\"\n\n{-- Lists, Tuples, and Records --}\n\n-- Every element in a list must have the same type.\n[\"the\", \"quick\", \"brown\", \"fox\"]\n[1, 2, 3, 4, 5]\n-- The second example can also be written with two dots.\nList.range 1 5\n\n-- Append lists just like strings.\nList.range 1 5 ++ List.range 6 10 == List.range 1 10 -- True\n\n-- To add one item, use \"cons\".\n0 :: List.range 1 5 -- [0, 1, 2, 3, 4, 5]\n\n-- The head and tail of a list are returned as a Maybe. Instead of checking\n-- every value to see if it's null, you deal with missing values explicitly.\nList.head (List.range 1 5) -- Just 1\nList.tail (List.range 1 5) -- Just [2, 3, 4, 5]\nList.head [] -- Nothing\n-- List.functionName means the function lives in the List module.\n\n-- Every element in a tuple can be a different type, but a tuple has a\n-- fixed length.\n(\"elchemy\", 42)\n\n-- Access the elements of a pair with the first and second functions.\n-- (This is a shortcut; we'll come to the \"real way\" in a bit.)\nTuple.first (\"elchemy\", 42) -- \"elchemy\"\nTuple.second (\"elchemy\", 42) -- 42\n\n-- The empty tuple, or \"unit\", is sometimes used as a placeholder.\n-- It is the only value of its type, also called \"Unit\".\n()\n\n-- Records are like tuples but the fields have names. The order of fields\n-- doesn't matter. Notice that record values use equals signs, not colons.\n{ x = 3, y = 7 }\n\n-- Access a field with a dot and the field name.\n{ x = 3, y = 7 }.x -- 3\n\n-- Or with an accessor function, which is a dot and the field name on its own.\n.y { x = 3, y = 7 } -- 7\n\n-- Update the fields of a record. (It must have the fields already.)\n{ person |\n  name = \"George\" }\n\n-- Update multiple fields at once, using the current values.\n{ particle |\n  position = particle.position + particle.velocity,\n  velocity = particle.velocity + particle.acceleration }\n\n{-- Control Flow --}\n\n-- If statements always have an else, and the branches must be the same type.\nif powerLevel > 9000 then\n  \"WHOA!\"\nelse\n  \"meh\"\n\n-- If statements can be chained.\nif n < 0 then\n  \"n is negative\"\nelse if n > 0 then\n  \"n is positive\"\nelse\n  \"n is zero\"\n\n-- Use case statements to pattern match on different possibilities.\ncase aList of\n  [] -> \"matches the empty list\"\n  [x]-> \"matches a list of exactly one item, \" ++ toString x\n  x::xs -> \"matches a list of at least one item whose head is \" ++ toString x\n-- Pattern matches go in order. If we put [x] last, it would never match because\n-- x::xs also matches (xs would be the empty list). Matches do not \"fall through\".\n-- The compiler will alert you to missing or extra cases.\n\n-- Pattern match on a Maybe.\ncase List.head aList of\n  Just x -> \"The head is \" ++ toString x\n  Nothing -> \"The list was empty.\"\n\n{-- Functions --}\n\n-- Elchemy's syntax for functions is very minimal, relying mostly on whitespace\n-- rather than parentheses and curly brackets. There is no \"return\" keyword.\n\n-- Define a function with its name, arguments, an equals sign, and the body.\nmultiply a b =\n  a * b\n\n-- Apply (call) a function by passing it arguments (no commas necessary).\nmultiply 7 6 -- 42\n\n-- Partially apply a function by passing only some of its arguments.\n-- Then give that function a new name.\ndouble =\n  multiply 2\n\n-- Constants are similar, except there are no arguments.\nanswer =\n  42\n\n-- Pass functions as arguments to other functions.\nList.map double (List.range 1 4) -- [2, 4, 6, 8]\n\n-- Or write an anonymous function.\nList.map (\\a -> a * 2) (List.range 1 4) -- [2, 4, 6, 8]\n\n-- You can also write operators as functions wrapping them in parens\nList.map ((+) 2) (List.range 1 4) -- [3, 4, 5, 6]\n\n-- You can pattern match in function definitions when there's only one case.\n-- This function takes one tuple rather than two arguments.\n-- This is the way you'll usually unpack/extract values from tuples.\narea (width, height) =\n  width * height\n\narea (6, 7) -- 42\n\n-- Use curly brackets to pattern match record field names.\n-- Use let to define intermediate values.\nvolume {width, height, depth} =\n  let\n    area = width * height\n  in\n    area * depth\n\nvolume { width = 3, height = 2, depth = 7 } -- 42\n\n-- Functions can be recursive.\nfib n =\n  if n < 2 then\n    1\n  else\n    fib (n - 1) + fib (n - 2)\n\nList.map fib (List.range 0 8) -- [1, 1, 2, 3, 5, 8, 13, 21, 34]\n\n-- Another recursive function (use List.length in real code).\nlistLength aList =\n  case aList of\n    [] -> 0\n    x::xs -> 1 + listLength xs\n\n-- Function calls happen before any infix operator. Parens indicate precedence.\ncos (degrees 30) ^ 2 + sin (degrees 30) ^ 2 -- 1\n-- First degrees is applied to 30, then the result is passed to the trig\n-- functions, which is then squared, and the addition happens last.\n\n{-- Types and Type Annotations --}\n\n-- The compiler will infer the type of every value in your program.\n-- Types are always uppercase. Read x : T as \"x has type T\".\n-- Some common types\n5 : Int\n6.7 : Float\n\"hello\" : String\nTrue : Bool\n\n-- Functions have types too. Read -> as \"goes to\". Think of the rightmost type\n-- as the type of the return value, and the others as arguments.\nnot : Bool -> Bool\nround : Float -> Int\n\n-- When you define a value, it's good practice to write its type above it.\n-- The annotation is a form of documentation, which is verified by the compiler.\ndouble : Int -> Int\ndouble x = x * 2\n\n-- Function arguments are passed in parentheses.\n-- Lowercase types are type variables: they can be any type, as long as each\n-- call is consistent.\nList.map : (a -> b) -> List a -> List b\n-- \"List dot map has type a-goes-to-b, goes to list of a, goes to list of b.\"\n\n-- There are three special lowercase types: number, comparable, and appendable.\n-- Numbers allow you to use arithmetic on Ints and Floats.\n-- Comparable allows you to order numbers and strings, like a < b.\n-- Appendable things can be combined with a ++ b.\n\n{-- Type Aliases and Union Types --}\n\n-- When you write a record or tuple, its type already exists.\n-- (Notice that record types use colon and record values use equals.)\norigin : { x : Float, y : Float, z : Float }\norigin =\n  { x = 0, y = 0, z = 0 }\n\n-- You can give existing types a nice name with a type alias.\ntype alias Point3D =\n  { x : Float, y : Float, z : Float }\n\n-- If you alias a record, you can use the name as a constructor function.\notherOrigin : Point3D\notherOrigin =\n  Point3D 0 0 0\n\n-- But it's still the same type, so you can equate them.\norigin == otherOrigin -- True\n\n-- By contrast, defining a union type creates a type that didn't exist before.\n-- A union type is so called because it can be one of many possibilities.\n-- Each of the possibilities is represented as a \"tag\".\ntype Direction =\n  North | South | East | West\n\n-- Tags can carry other values of known type. This can work recursively.\ntype IntTree =\n  Leaf | Node Int IntTree IntTree\n-- \"Leaf\" and \"Node\" are the tags. Everything following a tag is a type.\n\n-- Tags can be used as values or functions.\nroot : IntTree\nroot =\n  Node 7 Leaf Leaf\n\n-- Union types (and type aliases) can use type variables.\ntype Tree a =\n  Leaf | Node a (Tree a) (Tree a)\n-- \"The type tree-of-a is a leaf, or a node of a, tree-of-a, and tree-of-a.\"\n\n-- Pattern match union tags. The uppercase tags will be matched exactly. The\n-- lowercase variables will match anything. Underscore also matches anything,\n-- but signifies that you aren't using it.\nleftmostElement : Tree a -> Maybe a\nleftmostElement tree =\n  case tree of\n    Leaf -> Nothing\n    Node x Leaf _ -> Just x\n    Node _ subtree _ -> leftmostElement subtree\n\n-- That's pretty much it for the language itself. Now let's see how to organize\n-- and run your code.\n\n{-- Modules and Imports --}\n\n-- The core libraries are organized into modules, as are any third-party\n-- libraries you may use. For large projects, you can define your own modules.\n\n-- Put this at the top of the file. If omitted, you're in Main.\nmodule Name\n\n-- By default, everything is exported. You can specify exports explicitly.\nmodule Name exposing (MyType, myValue)\n\n-- Import a type and all it's Tags\nimport Name exposing (MyType(..))\n\n-- One common pattern is to export a union type but not its tags. This is known\n-- as an \"opaque type\", and is frequently used in libraries.\n\n-- Import code from other modules to use it in this one.\n-- Places Dict in scope, so you can call Dict.insert.\nimport Dict\n\n-- Imports the Dict module and the Dict type, so your annotations don't have to\n-- say Dict.Dict. You can still use Dict.insert.\nimport Dict exposing (Dict)\n\n\n{-- Command Line Tools --}\n\n-- Install in a project\n$ elchemy init\n\n```\n\n"
  },
  {
    "path": "roadmap/TESTING.md",
    "content": "# Testing\n\nSo far there is no unit testing tool for Elchemy.  \nTo test your code use Elixir's `ExUnit` or see document [COMMENTS.md](COMMENTS.md) for using Doctests.\n"
  },
  {
    "path": "roadmap/TROUBLESHOOTING.md",
    "content": "# Troubleshooting\n\nGenerally grand amount of problems can be solved with a simple command:\n```\nelchemy clean\n```\n\nIt cleans all of the caches, temporary files, dependencies and code file outputs out of the current project.\n\nIf\n```\nelchemy clean\nelchemy init\nmix compile\n```\n\nstill yields compilation errors feel free to report an issue.\nFor the sake of being able to reproduce please provide:\n\n- Elchemy version (`elchemy version`)\n- Elixir version (`elixir -v`)\n- Erlang version (first line in `erl`)\n- Elm version (`elm -v`)\n- Operating system (`uname -msr`)\n\nIt's also helpful to include:\n- Result of `tree -L 2` inside your project folder\n- Code of the file failing\n"
  },
  {
    "path": "roadmap/TYPES.md",
    "content": "# Union types\n\nElchemy (exactly like Elm) uses [Tagged union types](https://en.wikipedia.org/wiki/Tagged_union) \nWhat it means is basically you can define a type by adding a tag to\nan already existing value and the meaning of this tag is to inform about the\ncontext of that value.\n\nFor instance:\n\n``` elm\ntype Shape = Dot Int | Line Int Int | Triangle Int Int Int\n```\nWhat's important is that Dot, Line and Triangle are just tags, so they can't be used as a type name (in function signatures for example)\nThe only purpose of these is to pattern match on them in constructs like case..of, let..in or in arguments\n\nElchemy represents tagged unions as tuples with a first element being an atom with snake_cased tag name, or - in case of just tags - as a single atom value.\n\nFor example our previously defined type would translate to:\n\n``` elixir\n@type shape :: { :dot, integer() } |\n               { :line, integer(), integer() } |\n               { :triangle, integer(), integer(), integer() }\n```\nBut a type like this:\n\n``` elm\ntype Size = XS | S | M | L | XL\n```\nWould translate to:\n\n``` elixir\n@type size :: :xs | :s | :m | :l | :xl\n```\n### Type Parameters\n\nTypes can also take type parameters like:\n\n``` elm\ntype Maybe x = Just x | Nothing\n```\nAll type parameters will resolve to any() by Elchemy.\n\n### Types as constructors\n\nA Type can be insinstantiated using a tag and values. \n\nFor example to instantiate `Just Int` we would write `Just 10`.\nIf you don't provide all of the parameters, Elchemy will recognize it and\ntranslate it into a curried function, so that 'Just' instead turning into;\n\n``` elixir\n:just\n```\n\nturns into:\n\n``` elixir\nfn x1 -> {:just, x1} end\n```\n"
  },
  {
    "path": "roadmap/TYPE_ALIASES.md",
    "content": "# Type Aliases\n\nIn Elchemy Type Aliases are completely virtual constructs that never make it out of the compiler.\nHowever whenever a type alias is used throughout your code Elchemy will expand the alias and substitute with the right replacement.\n\nFor instance if we write\n\n``` elm\ntype alias MyList = List Int\n\na : MyList\na = [1, 2, 3]\n```\n\nThe Elixir output would be\n\n``` elixir\n@spec a :: list(integer())\ndef a(), do: [1, 2, 3]\n```\nWith correct type resolution\n\n\n## Type aliases as constructors\n\nIf a type alias represents a structure like\n\n``` elm\ntype alias Human = { name : String, age : Int }\n```\nYou can use the name of an alias as a function to quickly instatiate a struct\n. For instance:\n\n``` elm\nHuman \"Krzysztof\" 22\n```\n"
  },
  {
    "path": "src/Elchemy/Alias.elm",
    "content": "module Elchemy.Alias exposing (registerAliases, replaceTypeAliases, resolveTypeBody)\n\nimport Ast.Statement exposing (Statement(..), Type(..))\nimport Dict exposing (Dict)\nimport Elchemy.Ast as Ast\nimport Elchemy.Context as Context\n    exposing\n        ( Alias\n        , AliasType\n        , Context\n        , TypeBody(..)\n        , wrongArityAlias\n        )\nimport Elchemy.Helpers as Helpers exposing ((=>), lastAndRest)\n\n\nregisterAliases : Context -> List Statement -> Context\nregisterAliases c list =\n    List.foldl registerAlias c list\n\n\nregisterAlias : Statement -> Context -> Context\nregisterAlias s c =\n    case s of\n        TypeAliasDeclaration tc t ->\n            registerTypeAlias c tc t\n\n        TypeDeclaration tc types ->\n            registerUnionType c tc types\n\n        FunctionTypeDeclaration name t ->\n            registerFunctionDefinition c name t\n\n        _ ->\n            c\n\n\nresolveTypeBody : Context -> TypeBody -> List Type -> Type\nresolveTypeBody c typeBody givenArgs =\n    case typeBody of\n        SimpleType t ->\n            t\n\n        ArgumentedType name expectedArgs return ->\n            let\n                arity =\n                    List.length givenArgs\n\n                expected =\n                    List.length expectedArgs\n            in\n                if arity == expected then\n                    resolveTypes c expectedArgs givenArgs return\n                else\n                    wrongArityAlias c expected givenArgs name\n\n\nregisterTypeAlias : Context -> Type -> Type -> Context\nregisterTypeAlias c tc t =\n    case tc of\n        TypeConstructor [ name ] arguments ->\n            let\n                arity =\n                    List.length arguments\n\n                typeBody =\n                    ArgumentedType name arguments t\n\n                ali =\n                    Alias c.mod arity Context.TypeAlias t typeBody []\n            in\n                Context.addAlias c.mod name ali c\n\n        ts ->\n            Context.crash c <| \"Wrong type alias declaration \" ++ toString ts\n\n\nregisterUnionType : Context -> Type -> List Type -> Context\nregisterUnionType c tc types =\n    case tc of\n        TypeConstructor [ name ] arguments ->\n            let\n                typeVar =\n                    TypeVariable <| \"@\" ++ name\n\n                arity =\n                    List.length arguments\n\n                ( names, newC ) =\n                    registerTypes types name c\n\n                ali =\n                    Alias c.mod arity Context.Type typeVar (SimpleType typeVar) names\n            in\n                Context.addAlias c.mod name ali newC\n\n        ts ->\n            Context.crash c <| \"Wrong type declaration \" ++ toString ts\n\n\nregisterFunctionDefinition : Context -> String -> Type -> Context\nregisterFunctionDefinition c name t =\n    let\n        arity =\n            replaceTypeAliases c t\n                |> Helpers.typeApplicationToList\n                |> List.length\n    in\n        Context.addFunctionDefinition c name (Context.FunctionDefinition (arity - 1) t)\n\n\nregisterTypes : List Type -> String -> Context -> ( List String, Context )\nregisterTypes types parentAlias c =\n    let\n        addType t ( names, context ) =\n            case t of\n                TypeConstructor [ name ] args ->\n                    (name :: names)\n                        => Context.addType c.mod parentAlias name (List.length args) context\n\n                any ->\n                    Context.crash c \"Type can only start with a tag\"\n    in\n        List.foldl addType ( [], c ) types\n\n\n{-| Function taking a type and replacing all aliases it points to with their dealiased version\n-}\nreplaceTypeAliases : Context -> Type -> Type\nreplaceTypeAliases c t =\n    let\n        mapOrFunUpdate mod default typeName args =\n            Context.getAlias mod typeName c\n                |> Helpers.filterMaybe (.aliasType >> (==) Context.TypeAlias)\n                |> Maybe.map (\\{ typeBody } -> resolveTypeBody c typeBody args)\n                |> Maybe.andThen\n                    (\\body ->\n                        case body of\n                            TypeRecordConstructor _ _ ->\n                                Just body\n\n                            TypeApplication _ _ ->\n                                Just body\n\n                            _ ->\n                                Nothing\n                    )\n                |> Maybe.withDefault default\n\n        typeConstructorReplace default fullType args =\n            Helpers.moduleAccess c.mod fullType\n                |> (\\( mod, typeName ) -> mapOrFunUpdate mod default typeName args)\n\n        replaceAlias t =\n            case t of\n                TypeConstructor fullType args ->\n                    typeConstructorReplace t fullType args\n\n                t ->\n                    t\n    in\n        Ast.walkTypeOutwards replaceAlias t\n\n\nresolveTypes : Context -> List Type -> List Type -> Type -> Type\nresolveTypes c expected given return =\n    let\n        expectedName n =\n            case n of\n                TypeVariable name ->\n                    name\n\n                other ->\n                    Context.crash c <|\n                        \"type can only take variables. \"\n                            ++ toString other\n                            ++ \"is incorrect\"\n\n        paramsWithResolution =\n            List.map2 (,) (List.map expectedName expected) given\n                |> List.foldl (uncurry Dict.insert) Dict.empty\n\n        replace t =\n            case t of\n                (TypeVariable name) as default ->\n                    Dict.get name paramsWithResolution\n                        |> Maybe.withDefault default\n\n                t ->\n                    t\n    in\n        Ast.walkTypeOutwards replace return\n\n\n{-| Resolve an alias from local context\n-}\nlocalAlias : String -> Context -> Maybe Alias\nlocalAlias name context =\n    Context.getAlias context.mod name context\n"
  },
  {
    "path": "src/Elchemy/Ast.elm",
    "content": "module Elchemy.Ast exposing (foldExpression, walkExpressionInwards, walkExpressionOutwards, walkTypeInwards, walkTypeOutwards)\n\n{-| Contains helper functions to manage Elm Expression and Statement.Type ASTs\n-}\n\nimport Ast.Expression exposing (Expression(..))\nimport Ast.Statement exposing (Type(..))\n\n\n{-| Walks a tree of Ast.Statement.Type starting from the bottom branches and goes to the top using a replacer function\n-}\nwalkTypeOutwards : (Type -> Type) -> Type -> Type\nwalkTypeOutwards f t =\n    f <| walkType (walkTypeOutwards f) t\n\n\n{-| Walks a tree of Ast.Statement.Type starting from the top and goes down the branches using a replacer function\n-}\nwalkTypeInwards : (Type -> Type) -> Type -> Type\nwalkTypeInwards f t =\n    f t |> walkType (walkTypeInwards f)\n\n\nwalkType : (Type -> Type) -> Type -> Type\nwalkType walkFunction t =\n    case t of\n        (TypeVariable name) as x ->\n            x\n\n        TypeConstructor modulePathAndName args ->\n            TypeConstructor modulePathAndName (List.map walkFunction args)\n\n        TypeRecordConstructor name args ->\n            TypeRecordConstructor (walkFunction name) <|\n                List.map (Tuple.mapSecond walkFunction) args\n\n        TypeTuple args ->\n            TypeTuple <| List.map walkFunction args\n\n        TypeRecord args ->\n            TypeRecord <| List.map (Tuple.mapSecond walkFunction) args\n\n        TypeApplication l r ->\n            TypeApplication (walkFunction l) (walkFunction r)\n\n\n{-| Walks a tree of Ast.Expression.Expression starting from the bottom branches and goes to the top using a replacer function\n-}\nwalkExpressionOutwards : (Expression -> Expression) -> Expression -> Expression\nwalkExpressionOutwards f t =\n    f <| walkExpression (walkExpressionOutwards f) t\n\n\n{-| Walks a tree of Ast.Expression.Expression starting from the top and goes down the branches using a replacer function\n-}\nwalkExpressionInwards : (Expression -> Expression) -> Expression -> Expression\nwalkExpressionInwards f t =\n    f t |> walkExpression (walkExpressionInwards f)\n\n\nwalkExpression : (Expression -> Expression) -> Expression -> Expression\nwalkExpression f t =\n    case f t of\n        (Variable _) as x ->\n            x\n\n        (Character _) as c ->\n            c\n\n        (String _) as s ->\n            s\n\n        (Integer _) as i ->\n            i\n\n        (Float _) as f ->\n            f\n\n        List exps ->\n            List (List.map (walkExpression f) exps)\n\n        Tuple exps ->\n            Tuple (List.map (walkExpression f) exps)\n\n        Access mod field ->\n            Access (walkExpression f mod) field\n\n        (AccessFunction field) as af ->\n            af\n\n        Record fields ->\n            Record <| List.map (Tuple.mapSecond <| walkExpression f) fields\n\n        RecordUpdate name fields ->\n            RecordUpdate name <| List.map (Tuple.mapSecond <| walkExpression f) fields\n\n        If check true false ->\n            If (walkExpression f check) (walkExpression f true) (walkExpression f false)\n\n        Let assignments body ->\n            Let (List.map (Tuple.mapSecond <| walkExpression f) assignments) (walkExpression f body)\n\n        Case target branches ->\n            Case (walkExpression f target) (List.map (\\( l, r ) -> ( walkExpression f l, walkExpression f r )) branches)\n\n        Lambda args body ->\n            Lambda (List.map (walkExpression f) args) (walkExpression f body)\n\n        Application left right ->\n            Application (walkExpression f left) (walkExpression f right)\n\n        BinOp op left right ->\n            BinOp (walkExpression f op) (walkExpression f left) (walkExpression f right)\n\n\n{-| Walks a tree of Ast.Expression.Expression starting from the top and goes down the branches using a folder function\n-}\nfoldExpression : (Expression -> acc -> acc) -> acc -> Expression -> acc\nfoldExpression f acc t =\n    let\n        rec =\n            flip <| foldExpression f\n    in\n        f t <|\n            case t of\n                Variable _ ->\n                    acc\n\n                Character _ ->\n                    acc\n\n                String _ ->\n                    acc\n\n                Integer _ ->\n                    acc\n\n                Float _ ->\n                    acc\n\n                List exps ->\n                    List.foldl rec acc exps\n\n                Tuple exps ->\n                    List.foldl rec acc exps\n\n                Access mod field ->\n                    rec mod acc\n\n                AccessFunction field ->\n                    acc\n\n                Record fields ->\n                    List.foldl (Tuple.second >> rec) acc fields\n\n                RecordUpdate name fields ->\n                    List.foldl (Tuple.second >> rec) acc fields\n\n                If check true false ->\n                    acc |> rec check |> rec true |> rec false\n\n                Let assignments body ->\n                    List.foldl (\\( a, b ) lAcc -> rec a lAcc |> rec b) acc assignments |> rec body\n\n                Case target branches ->\n                    acc |> rec target |> (\\nAcc -> List.foldl (\\( a, b ) lAcc -> rec a lAcc |> rec b) nAcc branches)\n\n                Lambda args body ->\n                    List.foldl rec acc args |> rec body\n\n                Application left right ->\n                    acc |> rec left |> rec right\n\n                BinOp op left right ->\n                    acc |> rec op |> rec left |> rec right\n"
  },
  {
    "path": "src/Elchemy/Compiler.elm",
    "content": "module Elchemy.Compiler exposing (version, tree)\n\n{-| Module responsible for compiling Elm code to Elixir\n\n@docs version, tree\n\n-}\n\nimport Ast\nimport Ast.Statement exposing (Statement)\nimport Dict exposing (Dict)\nimport Elchemy.Alias as Alias\nimport Elchemy.Context as Context exposing (Context)\nimport Elchemy.Helpers as Helpers exposing (ind, toSnakeCase)\nimport Elchemy.Meta as Meta\nimport Elchemy.Statement as Statement\nimport Regex exposing (HowMany(..), Regex, regex)\n\n\n{-| Returns current version\n-}\nversion : String\nversion =\n    \"0.8.8\"\n\n\nglueStart : String\nglueStart =\n    ind 0 ++ \"use Elchemy\" ++ \"\\n\"\n\n\nglueEnd : String\nglueEnd =\n    \"\\n\"\n        ++ String.trim\n            \"\"\"\n         end\n\n         \"\"\"\n        ++ \"\\n\"\n\n\ngetName : String -> ( String, String )\ngetName file =\n    case String.split \"\\n\" file of\n        n :: rest ->\n            ( n, String.join \"\\n\" rest )\n\n        [] ->\n            ( \"\", \"\" )\n\n\n{-| Transforms a code in Elm to code in Elixir\n-}\ntree : String -> String\ntree =\n    treeAndCommons >> Tuple.first\n\n\n{-| Transforms a code in Elm to code in Elixir and returns commons\n-}\ntreeAndCommons : String -> ( String, Context.Commons )\ntreeAndCommons m =\n    fullTree Context.emptyCommons m\n\n\n{-| Transforms a code in Elm with cache from previous run to code in Elixir and cache\n-}\nfullTree : Context.Commons -> String -> ( String, Context.Commons )\nfullTree cachedCommons m =\n    -- If only no blank characters\n    if Regex.contains (Regex.regex \"^\\\\s*$\") m then\n        ( \"\", cachedCommons )\n    else if not <| String.contains (\">>\" ++ \">>\") m then\n        m\n            |> parse \"NoName.elm\"\n            |> getContext\n            |> (\\( c, a ) ->\n                    case c of\n                        Nothing ->\n                            Debug.crash \"Failed getting context\"\n\n                        Just c ->\n                            ( getCode c a, c.commons )\n               )\n    else\n        let\n            multiple =\n                String.split (\">>\" ++ \">>\") m\n\n            count =\n                Debug.log \"Number of files\" (List.length multiple)\n\n            files =\n                multiple\n                    |> List.map getName\n                    |> List.indexedMap (,)\n                    |> List.map\n                        (\\( i, ( name, code ) ) ->\n                            let\n                                _ =\n                                    flip Debug.log name <|\n                                        \"Parsing \"\n                                            ++ toString (count - i)\n                                            ++ \"/\"\n                                            ++ toString count\n                                            ++ \" # \"\n                            in\n                                ( name, parse name code )\n                        )\n\n            wContexts =\n                files\n                    |> List.map (\\( name, ast ) -> ( name, getContext ast ))\n                    |> List.filterMap\n                        (\\a ->\n                            case a of\n                                ( _, ( Nothing, _ ) ) ->\n                                    Nothing\n\n                                ( name, ( Just c, ast ) ) ->\n                                    Just ( name, c, ast )\n                        )\n\n            commons =\n                wContexts\n                    |> List.map (\\( name, ctx, ast ) -> ctx.commons)\n                    |> (::) cachedCommons\n                    |> getCommonImports\n                    |> (\\modules -> { modules = modules })\n\n            wTrueContexts =\n                wContexts\n                    |> List.map (\\( name, c, ast ) -> ( name, { c | commons = commons }, ast ))\n\n            compileWithIndex ( i, ( name, c, ast ) ) =\n                let\n                    _ =\n                        flip Debug.log name <|\n                            \"Compiling \"\n                                ++ toString (count - i)\n                                ++ \"/\"\n                                ++ toString count\n                                ++ \" # \"\n                in\n                    -- \"Used to avoid quadruple > becuase it's a meta string\"\n                    \">>\" ++ \">>\" ++ name ++ \"\\n\" ++ getCode c ast\n        in\n            wTrueContexts\n                |> List.indexedMap (,)\n                |> List.map compileWithIndex\n                |> String.join \"\\n\"\n                |> flip (,) commons\n\n\ngetCommonImports : List Context.Commons -> Dict String Context.Module\ngetCommonImports commons =\n    let\n        merge aliases acc =\n            Dict.merge Dict.insert (\\k v v2 -> Dict.insert k v2) Dict.insert acc aliases Dict.empty\n    in\n        List.foldl (.modules >> merge) Dict.empty commons\n\n\ngetContext : List Statement -> ( Maybe Context, List Statement )\ngetContext statements =\n    case statements of\n        [] ->\n            ( Nothing, [] )\n\n        mod :: statements ->\n            let\n                base =\n                    Statement.moduleStatement mod\n            in\n                ( Just (Alias.registerAliases base statements), statements )\n\n\naggregateStatements : Statement -> ( Context, String ) -> ( Context, String )\naggregateStatements s ( c, code ) =\n    let\n        ( newC, newCode ) =\n            Statement.elixirS c s\n    in\n        ( newC, code ++ newCode )\n\n\ngetCode : Context -> List Statement -> String\ngetCode context statements =\n    let\n        shadowsBasics =\n            Context.importBasicsWithoutShadowed context\n\n        ( newC, code ) =\n            List.foldl aggregateStatements ( context, \"\" ) statements\n    in\n        (\"# Compiled using Elchemy v\" ++ version)\n            ++ \"\\n\"\n            ++ (\"defmodule \" ++ context.mod ++ \" do\")\n            ++ glueStart\n            ++ ind context.indent\n            ++ shadowsBasics\n            ++ code\n            ++ glueEnd\n            ++ Meta.metaDefinition { newC | inMeta = True }\n            ++ \"\\n\\n\"\n\n\nparse : String -> String -> List Statement\nparse fileName code =\n    case Ast.parse (prepare code) of\n        Ok ( _, _, statements ) ->\n            statements\n\n        Err ( (), { input, position }, [ msg ] ) ->\n            let\n                ( line, column ) =\n                    getLinePosition position code\n            in\n                Debug.crash <|\n                    \"]ERR> Parsing error in:\\n \"\n                        ++ fileName\n                        ++ \":\"\n                        ++ toString line\n                        ++ \":\"\n                        ++ toString column\n                        ++ \"\\n\"\n                        ++ msg\n                        ++ \"\\nat:\\n \"\n                        ++ (input\n                                |> String.lines\n                                |> List.take 30\n                                |> String.join \"\\n\"\n                           )\n                        ++ \"\\n\"\n\n        err ->\n            Debug.crash (toString err)\n\n\nprepare : String -> String\nprepare codebase =\n    codebase |> removeComments\n\n\nremoveComments : String -> String\nremoveComments =\n    Regex.replace All (regex \" +--.*\\\\r?\\\\n\") (always \"\")\n        >> Regex.replace All (regex \"\\\\s--.*\\\\r?\\\\n\") (always \"\")\n        >> Regex.replace All (regex \"\\n +\\\\w+ : .*\") (always \"\")\n\n\ngetLinePosition : Int -> String -> ( Int, Int )\ngetLinePosition character input =\n    let\n        lines =\n            String.slice 0 character input |> String.lines\n\n        line =\n            List.length lines\n\n        column =\n            List.reverse lines |> List.head |> Maybe.map String.length |> Maybe.withDefault 0\n    in\n        ( line, column )\n"
  },
  {
    "path": "src/Elchemy/Context.elm",
    "content": "module Elchemy.Context\n    exposing\n        ( Alias\n        , AliasType(..)\n        , Commons\n        , Context\n        , FunctionDefinition\n        , Module\n        , Parser\n        , TypeBody(..)\n        , addAlias\n        , addFlag\n        , addFunctionDefinition\n        , addModuleAlias\n        , addType\n        , areMatchingArity\n        , changeCurrentModule\n        , crash\n        , deindent\n        , empty\n        , emptyCommons\n        , getAlias\n        , getArity\n        , getShadowedFunctions\n        , getType\n        , hasFlag\n        , importBasicsWithoutShadowed\n        , inArgs\n        , indent\n        , isPrivate\n        , listOfImports\n        , maybeModuleAlias\n        , mergeTypes\n        , mergeVariables\n        , notImplemented\n        , onlyWithoutFlag\n        , putIntoModule\n        , wrongArityAlias\n        )\n\nimport Ast.Expression exposing (Expression)\nimport Ast.Statement exposing (ExportSet(..), Statement, Type(..))\nimport Dict exposing (Dict)\nimport Elchemy.Helpers as Helpers exposing (toSnakeCase)\nimport Set exposing (Set)\n\n\ntype alias Parser =\n    Context -> Expression -> String\n\n\n{-| A structure containing all the essential information about Type Alias\n-}\ntype TypeBody\n    = SimpleType Type\n    | ArgumentedType String (List Type) Type\n\n\ntype alias Alias =\n    { parentModule : String\n    , arity : Int\n    , aliasType : AliasType\n    , body : Type\n    , typeBody : TypeBody\n    , types : List String\n    }\n\n\ntype alias UnionType =\n    { arity : Int\n    , parentModule : String\n    , parentAlias : String\n    }\n\n\n{-| Type of an Alias which can be either Type or Type Alias. It's important to note\nthat a Type in here is only a definition of a type like\n\n    type A\n        = TagA\n        | TagB\n\nWhere only A is a `Context.AliasType.Type`, two separate tags are other instances and\nbelong to Types not Aliases\n\n-}\ntype AliasType\n    = Type\n    | TypeAlias\n\n\n{-| A flag for a compiler and its value\n-}\ntype alias Flag =\n    ( String, String )\n\n\n{-| Definition of a function and its correspoint Ast.Type structure\n-}\ntype alias FunctionDefinition =\n    { arity : Int, def : Ast.Statement.Type }\n\n\n{-| Dict holding information about defined modules\n-}\ntype alias Module =\n    { aliases : Dict String Alias\n    , types : Dict String UnionType\n    , functions : Dict String FunctionDefinition\n    , exports : ExportSet\n    }\n\n\ntype alias Commons =\n    { modules : Dict String Module\n    }\n\n\n{-| Context containing all the necessary information about current place in a file\nlike what's the name of a module, what aliases, types and variables are currently defined,\nwhat flags were set for the compiler, what functions were defined and if it is in definition mode.\n-}\ntype alias Context =\n    { mod : String\n    , commons : Commons\n    , exports : ExportSet\n    , indent : Int\n    , flags : List Flag\n    , variables : Set String\n    , inArgs : Bool\n    , hasModuleDoc : Bool\n    , lastDoc : Maybe String\n    , inTypeDefiniton : Bool\n    , importedTypes : Dict String String\n    , aliasedModules : Dict String String\n\n    -- Dict functionName (moduleName, arity)\n    , importedFunctions : Dict String ( String, Int )\n    , meta : Maybe Expression\n    , inMeta : Bool\n    }\n\n\n{-| Crashes the compiler because the alias was used with wrong arity.\nShouldn't ever happen if run after elm-make\n-}\nwrongArityAlias : Context -> Int -> List Type -> String -> a\nwrongArityAlias c arity list name =\n    crash c <|\n        \"Expected \"\n            ++ toString arity\n            ++ \" arguments for \"\n            ++ name\n            ++ \". But got \"\n            ++ (toString <| List.length list)\n\n\n{-| Puts something into module\nUsage:\n\n    putIntoModule \"Module\" \"name\" .aliases (x -> { c | aliases = x }) ali c\n\n-}\nputIntoModule :\n    String\n    -> String\n    -> (Module -> Dict String a)\n    -> (Module -> Dict String a -> Module)\n    -> a\n    -> Context\n    -> Context\nputIntoModule mod name getter setter thing c =\n    let\n        updateMod : Maybe Module -> Maybe Module\n        updateMod maybeMod =\n            maybeMod\n                |> Maybe.map getter\n                |> Maybe.withDefault Dict.empty\n                |> Dict.update name (always <| Just thing)\n                |> setter (maybeMod |> Maybe.withDefault emptyModule)\n                |> Just\n\n        commons =\n            c.commons\n    in\n        { c | commons = { commons | modules = commons.modules |> Dict.update mod updateMod } }\n\n\n{-| Adds an alias definition to the context\n-}\naddAlias : String -> String -> Alias -> Context -> Context\naddAlias mod name =\n    putIntoModule mod name .aliases (\\m x -> { m | aliases = x })\n\n\n{-| Adds a type definition to the context\n-}\naddType : String -> String -> String -> Int -> Context -> Context\naddType mod parentAlias name arity =\n    let\n        t =\n            { arity = arity, parentModule = mod, parentAlias = parentAlias }\n    in\n        putIntoModule mod name .types (\\m x -> { m | types = x }) t\n\n\n{-| Add type definition into context\n-}\naddFunctionDefinition : Context -> String -> FunctionDefinition -> Context\naddFunctionDefinition c name d =\n    putIntoModule c.mod name .functions (\\m x -> { m | functions = x }) d c\n\n\n{-| Get's either alias or type from context based on `from` accessor\n-}\ngetFromContext :\n    (Module -> Dict String a)\n    -> String\n    -> String\n    -> Context\n    -> Maybe a\ngetFromContext from mod name context =\n    context\n        |> .commons\n        |> .modules\n        |> Dict.get mod\n        |> Maybe.map from\n        |> Maybe.andThen (Dict.get name)\n\n\n{-| Get's an alias from context based on name of a module and of an alias\nWrapped in Maybe\n-}\ngetAlias : String -> String -> Context -> Maybe Alias\ngetAlias =\n    getFromContext .aliases\n\n\n{-| Get's a type from context based on name of a module and of a type\nWrapped in Maybe\n-}\ngetType : String -> String -> Context -> Maybe UnionType\ngetType =\n    getFromContext .types\n\n\n{-| Gets arity of the function in the module\n-}\ngetArity : Context -> String -> String -> Maybe Int\ngetArity ctx m fn =\n    let\n        local =\n            ctx.commons.modules\n                |> Dict.get m\n                |> Maybe.map .functions\n                |> Maybe.andThen (Dict.get fn)\n                |> Maybe.map .arity\n\n        imported =\n            ctx.importedFunctions\n                |> Dict.get fn\n                |> Maybe.map Tuple.second\n    in\n        Helpers.maybeOr local imported\n\n\n{-| Checks if function arity stored in context is the same as arguments count\n-}\nareMatchingArity : Context -> String -> String -> List a -> Bool\nareMatchingArity c mod fn args =\n    List.length args == Maybe.withDefault -1 (getArity c mod fn)\n\n\n{-| Returns empty context\n-}\nempty : String -> ExportSet -> Context\nempty name exports =\n    { mod = name\n    , exports = exports\n    , indent = 0\n    , flags = []\n    , variables = Set.empty\n    , inArgs = False\n    , hasModuleDoc = False\n    , lastDoc = Nothing\n    , commons = { modules = Dict.singleton name (Module Dict.empty Dict.empty Dict.empty exports) }\n    , inTypeDefiniton = False\n    , importedTypes =\n        Dict.fromList\n            [ ( \"Order\", \"Elchemy.XBasics\" )\n            , ( \"Result\", \"Elchemy.XResult\" )\n            ]\n    , importedFunctions = Dict.empty\n    , aliasedModules = Dict.empty\n    , meta = Nothing\n    , inMeta = False\n    }\n\n\n{-| Returns empty commons structure\n-}\nemptyCommons : Commons\nemptyCommons =\n    { modules = Dict.empty\n    }\n\n\nchangeCurrentModule : String -> Context -> Context\nchangeCurrentModule mod c =\n    { c | mod = mod }\n\n\n{-| Returns empty module record\n-}\nemptyModule : Module\nemptyModule =\n    Module Dict.empty Dict.empty Dict.empty AllExport\n\n\n{-| Increases current indenation level of a context\n-}\nindent : Context -> Context\nindent c =\n    { c | indent = c.indent + 1 }\n\n\n{-| Decreases current indenation level of a context\n-}\ndeindent : Context -> Context\ndeindent c =\n    { c | indent = c.indent - 1 }\n\n\n{-| Adds a flag to the compiler of a context\n-}\naddFlag : Flag -> Context -> Context\naddFlag flag c =\n    { c | flags = flag :: c.flags }\n\n\n{-| Puts the code only if the given flag and its given value DOESN'T exist\n-}\nonlyWithoutFlag : Context -> String -> String -> String -> String\nonlyWithoutFlag c key value code =\n    if hasFlag key value c then\n        \"\"\n    else\n        code\n\n\n{-| -}\ngetAllFlags : String -> Context -> List String\ngetAllFlags key c =\n    c.flags\n        |> List.filter (Tuple.first >> (==) key)\n        |> List.map Tuple.second\n\n\n{-| True if has a flag with a particular value\n-}\nhasFlag : String -> String -> Context -> Bool\nhasFlag key value c =\n    c.flags\n        |> List.any ((==) ( key, value ))\n\n\n{-| Makes the state to be inside argument declaration,\nthanks to that the compiler knows not to treat the declaration of new variables\nas a refference to an older values or functions and prevents injection of parens\n-}\ninArgs : Context -> Context\ninArgs c =\n    { c | inArgs = True }\n\n\n{-| Tells you if a function is private or public based on context of a module\n-}\nisPrivate : Context -> String -> Bool\nisPrivate context name =\n    case context.exports of\n        SubsetExport exports ->\n            if List.any ((==) (FunctionExport name)) exports then\n                False\n            else\n                True\n\n        AllExport ->\n            False\n\n        other ->\n            crash context \"No such export\"\n\n\n{-| Merges a set of two variables from two different contexts\n-}\nmergeVariables : Context -> Context -> Context\nmergeVariables left right =\n    { left | variables = Set.union left.variables right.variables }\n\n\n{-| Finds all defined functions and all auto imported functions (XBasics) and returns\nthe commons subset. Return empty list for XBasics\n-}\ngetShadowedFunctions : Context -> List String -> List ( String, FunctionDefinition )\ngetShadowedFunctions context list =\n    let\n        functions =\n            context.commons.modules\n                |> Dict.get context.mod\n                |> Maybe.map .functions\n                |> Maybe.withDefault Dict.empty\n\n        findReserved name =\n            functions\n                |> Dict.get name\n                |> Maybe.map ((,) name >> List.singleton)\n                |> Maybe.withDefault []\n    in\n        if context.mod == \"Elchemy.XBasics\" then\n            []\n        else\n            list\n                |> List.concatMap findReserved\n\n\n{-| Changes function definitions to a list of qualified imports including 0 and full arity\n-}\nlistOfImports : List ( String, FunctionDefinition ) -> List String\nlistOfImports shadowed =\n    let\n        importTuple ( name, arity ) =\n            toSnakeCase False name\n                ++ \": 0, \"\n                ++ toSnakeCase False name\n                ++ \": \"\n                ++ toString arity\n    in\n        shadowed\n            |> List.map (Tuple.mapSecond .arity)\n            |> List.map importTuple\n\n\n{-| Get code representation of import XBasics with exclusion of functions defined locally\n-}\nimportBasicsWithoutShadowed : Context -> String\nimportBasicsWithoutShadowed c =\n    let\n        importModule mod list =\n            if list /= [] then\n                list\n                    |> String.join \", \"\n                    |> (++) (\"import \" ++ mod ++ \", except: [\")\n                    |> flip (++) \"]\\n\"\n            else\n                \"\"\n\n        shadowedBasics =\n            getShadowedFunctions c Helpers.reservedBasicFunctions\n                |> listOfImports\n\n        shadowedKernel =\n            getShadowedFunctions c Helpers.reservedKernelFunctions\n                |> listOfImports\n    in\n        importModule \"Elchemy.XBasics\" shadowedBasics\n            ++ importModule \"Kernel\" shadowedKernel\n\n\n{-| Register a new module alias\nimport ModuleA as ModuleB\nWould delias all ModuleB calls to ModuleA in case of Type and TypeAlias constructors\n-}\naddModuleAlias : String -> Maybe String -> Context -> Context\naddModuleAlias oldName newName c =\n    newName\n        |> Maybe.map (\\name -> { c | aliasedModules = c.aliasedModules |> Dict.insert name oldName })\n        |> Maybe.withDefault c\n\n\n{-| Replace a module name with it's original name it aliases to. Otherwise return the same name\n-}\nmaybeModuleAlias : Context -> String -> String\nmaybeModuleAlias c s =\n    c.aliasedModules\n        |> Dict.get s\n        |> Maybe.withDefault s\n\n\n{-| Merges everything that should be imported from given module, based\non given export set value\n-}\nmergeTypes : ExportSet -> String -> Context -> Context\nmergeTypes set mod c =\n    let\n        getAll getter mod =\n            c.commons.modules\n                |> Dict.get mod\n                |> Maybe.map getter\n                |> Maybe.withDefault Dict.empty\n\n        getAlias : String -> Dict String Alias\n        getAlias aliasName =\n            getAll .aliases mod\n                |> Dict.filter (\\k _ -> k == aliasName)\n\n        getTypes : String -> Maybe ExportSet -> Dict String UnionType\n        getTypes aliasName maybeExportSet =\n            getAll .types mod\n                |> Dict.filter (\\k { parentAlias } -> parentAlias == aliasName)\n\n        putAllLocal getter setter dict c =\n            Dict.foldl (\\key value acc -> putIntoModule c.mod key getter setter value acc) c dict\n\n        importOne export c =\n            case export of\n                TypeExport aliasName types ->\n                    c\n                        |> putAllLocal .aliases (\\m x -> { m | aliases = x }) (getAlias aliasName)\n                        |> putAllLocal .types (\\m x -> { m | types = x }) (getTypes aliasName types)\n\n                FunctionExport _ ->\n                    c\n\n                _ ->\n                    crash c \"You can't import subset of subsets\"\n    in\n        case set of\n            AllExport ->\n                c\n                    |> putAllLocal .aliases (\\m x -> { m | aliases = x }) (getAll .aliases mod)\n                    |> putAllLocal .types (\\m x -> { m | types = x }) (getAll .types mod)\n\n            SubsetExport list ->\n                List.foldl importOne c list\n\n            _ ->\n                crash c \"You can't import something that's not a subset\"\n\n\n{-| Throw a nice error with the context involving it\n-}\ncrash : Context -> String -> a\ncrash c prompt =\n    Debug.crash <|\n        \"Compilation error:\\n\\n\\t\"\n            ++ prompt\n            ++ \"\\n\\nin module: \"\n            ++ c.mod\n\n\n{-| Throw a nice error saying that this feature is not implemented yet\n-}\nnotImplemented : Context -> String -> a -> String\nnotImplemented c feature value =\n    \" ## ERROR: No \"\n        ++ feature\n        ++ \" implementation for \"\n        ++ toString value\n        ++ \" yet\"\n        ++ \"\\n\"\n        |> Debug.crash\n"
  },
  {
    "path": "src/Elchemy/Expression.elm",
    "content": "module Elchemy.Expression exposing (elixirE)\n\nimport Ast.Expression exposing (Expression(..))\nimport Elchemy.Context as Context\n    exposing\n        ( Context\n        , areMatchingArity\n        , deindent\n        , inArgs\n        , indent\n        , mergeVariables\n        , onlyWithoutFlag\n        )\nimport Elchemy.Operator as Operator\nimport Elchemy.Selector as Selector\nimport Elchemy.Type as Type\nimport Elchemy.Variable as Variable exposing (rememberVariables)\nimport Elchemy.Helpers as Helpers\n    exposing\n        ( (=>)\n        , Operator(..)\n        , applicationToList\n        , atomize\n        , generateArguments\n        , ind\n        , isCapitilzed\n        , lastAndRest\n        , maybeOr\n        , modulePath\n        , operatorType\n        , toSnakeCase\n        , translateOperator\n        )\n\n\n{-| Encode any given expression\n-}\nelixirE : Context -> Expression -> String\nelixirE c e =\n    case e of\n        Variable var ->\n            elixirVariable c var\n\n        -- Primitive types\n        (Application name arg) as application ->\n            tupleOrFunction c application\n\n        RecordUpdate name keyValuePairs ->\n            \"%{\"\n                ++ toSnakeCase True name\n                ++ \" | \"\n                ++ (List.map (\\( a, b ) -> toSnakeCase True a ++ \": \" ++ elixirE c b) keyValuePairs\n                        |> String.join \", \"\n                   )\n                ++ \"}\"\n\n        -- Primitive operators\n        Access (Variable modules) right ->\n            modulePath modules\n                ++ \".\"\n                ++ String.join \".\" (List.map (toSnakeCase True) right)\n\n        Access left right ->\n            elixirE c left\n                ++ \".\"\n                ++ String.join \".\" right\n\n        AccessFunction name ->\n            \"(fn a -> a.\" ++ toSnakeCase True name ++ \" end)\"\n\n        BinOp (Variable [ op ]) l r ->\n            Operator.elixirBinop c elixirE op l r\n\n        -- Rest\n        e ->\n            elixirControlFlow c e\n\n\n{-| Encode control flow expressions\n-}\nelixirControlFlow : Context -> Expression -> String\nelixirControlFlow c e =\n    case e of\n        Case var body ->\n            caseE c var body\n\n        Lambda args body ->\n            lambda c args body\n\n        (If check onTrue ((If _ _ _) as onFalse)) as exp ->\n            [ \"cond do\" ]\n                ++ handleIfExp (indent c) exp\n                ++ [ ind c.indent, \"end\" ]\n                |> String.join \"\"\n\n        If check onTrue onFalse ->\n            \"if \"\n                ++ elixirE c check\n                ++ \" do \"\n                ++ elixirE c onTrue\n                ++ \" else \"\n                ++ elixirE c onFalse\n                ++ \" end\"\n\n        Let variables expression ->\n            variables\n                |> Variable.organizeLetInVariablesOrder c\n                |> Variable.groupByCrossDependency\n                |> (flip List.foldl ( c, \"\" ) <|\n                        \\varGroup ( cAcc, codeAcc ) ->\n                            (case varGroup of\n                                [] ->\n                                    cAcc => \"\"\n\n                                [ ( var, exp ) ] ->\n                                    elixirLetInBranch cAcc ( var, exp )\n\n                                multiple ->\n                                    elixirLetInMutualFunctions cAcc multiple\n                            )\n                                |> (\\( c, string ) ->\n                                        mergeVariables c cAcc\n                                            => codeAcc\n                                            ++ string\n                                            ++ ind c.indent\n                                   )\n                   )\n                |> (\\( c, code ) -> code ++ elixirE c expression)\n\n        _ ->\n            elixirPrimitve c e\n\n\n{-| Encodes a mutual function usage into `let` macro\n-}\nelixirLetInMutualFunctions : Context -> List ( Expression, Expression ) -> ( Context, String )\nelixirLetInMutualFunctions context expressionsList =\n    let\n        vars =\n            List.map Tuple.first expressionsList\n\n        names =\n            expressionsList\n                |> List.map (Tuple.first >> Variable.extractName c >> toSnakeCase True)\n\n        c =\n            rememberVariables vars context\n\n        letBranchToLambda : Context -> ( Expression, Expression ) -> String\n        letBranchToLambda c ( head, body ) =\n            case applicationToList head of\n                [] ->\n                    \"\"\n\n                [ single ] ->\n                    elixirE c body\n\n                (Variable [ name ]) :: args ->\n                    lambda c args body\n\n                _ ->\n                    Context.crash c <| toString head ++ \" is not a let in branch\"\n    in\n        c\n            => \"{\"\n            ++ (names |> String.join \", \")\n            ++ \"} = let [\"\n            ++ (expressionsList\n                    |> List.map (\\(( var, exp ) as v) -> ( Variable.extractName c var, v ))\n                    |> List.map (Tuple.mapSecond <| letBranchToLambda (indent c))\n                    |> List.map (\\( name, body ) -> ind (c.indent + 1) ++ toSnakeCase True name ++ \": \" ++ body)\n                    |> String.join \",\"\n               )\n            ++ ind c.indent\n            ++ \"]\"\n\n\n{-| Encodes a branch of let..in expression\n\n    let\n      {a, b} == 2 --< This is a branch\n    in\n      10\n\n-}\nelixirLetInBranch : Context -> ( Expression, Expression ) -> ( Context, String )\nelixirLetInBranch c ( left, exp ) =\n    let\n        wrapElixirE c exp =\n            case exp of\n                Let _ _ ->\n                    \"(\" ++ ind (c.indent + 1) ++ elixirE (indent c) exp ++ ind c.indent ++ \")\"\n\n                _ ->\n                    elixirE c exp\n    in\n        case applicationToList left of\n            [ (Variable [ name ]) as var ] ->\n                rememberVariables [ var ] c\n                    => toSnakeCase True name\n                    ++ \" = \"\n                    ++ wrapElixirE (c |> rememberVariables [ var ]) exp\n\n            ((Variable [ name ]) as var) :: args ->\n                if Helpers.isCapitilzed name then\n                    (c |> rememberVariables args)\n                        => tupleOrFunction (rememberVariables args c) left\n                        ++ \" = \"\n                        ++ wrapElixirE c exp\n                else\n                    rememberVariables [ var ] c\n                        => toSnakeCase True name\n                        ++ \" = rec \"\n                        ++ toSnakeCase True name\n                        ++ \", \"\n                        ++ lambda (c |> rememberVariables [ var ]) args exp\n\n            [ assign ] ->\n                rememberVariables [ assign ] c\n                    => elixirE (inArgs c) assign\n                    ++ \" = \"\n                    ++ wrapElixirE (rememberVariables [ assign ] c) exp\n\n            _ ->\n                c => \"\"\n\n\n{-| Encode primitive value\n-}\nelixirPrimitve : Context -> Expression -> String\nelixirPrimitve c e =\n    case e of\n        Integer value ->\n            toString value\n\n        Float value ->\n            let\n                name =\n                    toString value\n            in\n                if String.contains \".\" name then\n                    name\n                else\n                    name ++ \".0\"\n\n        Character value ->\n            case value of\n                ' ' ->\n                    \"?\\\\s\"\n\n                '\\n' ->\n                    \"?\\\\n\"\n\n                '\\x0D' ->\n                    \"?\\\\r\"\n\n                '\\t' ->\n                    \"?\\\\t\"\n\n                '\\\\' ->\n                    \"?\\\\\\\\\"\n\n                '\\x00' ->\n                    \"?\\\\0\"\n\n                other ->\n                    \"?\" ++ String.fromChar other\n\n        String value ->\n            \"\\\"\" ++ value ++ \"\\\"\"\n\n        List vars ->\n            \"[\"\n                ++ (List.map (elixirE c) vars\n                        |> String.join \", \"\n                   )\n                ++ \"]\"\n\n        Tuple vars ->\n            \"{\"\n                ++ (List.map (elixirE c) vars\n                        |> String.join \", \"\n                   )\n                ++ \"}\"\n\n        Record keyValuePairs ->\n            \"%{\"\n                ++ (List.map (\\( a, b ) -> toSnakeCase True a ++ \": \" ++ elixirE c b) keyValuePairs\n                        |> String.join \", \"\n                   )\n                ++ \"}\"\n\n        _ ->\n            Context.notImplemented c \"expression\" e\n\n\n{-| Change if expression body into list of clauses\n-}\nhandleIfExp : Context -> Expression -> List String\nhandleIfExp c e =\n    case e of\n        If check onTrue onFalse ->\n            [ ind c.indent\n            , elixirE (indent c) check\n            , \" -> \"\n            , elixirE (indent c) onTrue\n            ]\n                ++ handleIfExp c onFalse\n\n        _ ->\n            [ ind c.indent\n            , \"true -> \"\n            , elixirE (indent c) e\n            ]\n\n\n{-| Returns if called function is a special macro inline by the compiler\n-}\nisMacro : Expression -> Bool\nisMacro e =\n    case e of\n        Application a _ ->\n            isMacro a\n\n        Variable [ x ] ->\n            List.member x\n                [ \"tryFfi\"\n                , \"ffi\"\n                , \"lffi\"\n                , \"macro\"\n                , \"flambda\"\n                , \"updateIn\"\n                , \"updateIn2\"\n                , \"updateIn3\"\n                , \"updateIn4\"\n                , \"updateIn5\"\n                , \"putIn\"\n                , \"putIn\"\n                , \"putIn2\"\n                , \"putIn3\"\n                , \"putIn4\"\n                , \"putIn5\"\n                , \"getIn\"\n                , \"getIn2\"\n                , \"getIn3\"\n                , \"getIn4\"\n                , \"getIn5\"\n                ]\n\n        other ->\n            False\n\n\n{-| Flattens Type application into a List of expressions or returns a singleton if it's not a type\n-}\nflattenApplication : Expression -> List Expression\nflattenApplication application =\n    case application of\n        Application left right ->\n            if isMacro application || isTuple application then\n                flattenApplication left ++ [ right ]\n            else\n                [ application ]\n\n        other ->\n            [ other ]\n\n\n{-| Returns uncurried function application if arguments length is matching definition arity\notherwise returns curried version\n-}\nfunctionApplication : Context -> Expression -> Expression -> String\nfunctionApplication c left right =\n    let\n        reduceArgs c args separator =\n            args |> List.map (elixirE c) |> String.join separator\n    in\n        case applicationToList (Application left right) of\n            (Variable [ fn ]) :: args ->\n                if areMatchingArity c c.mod fn args then\n                    toSnakeCase True fn ++ \"(\" ++ reduceArgs c args \", \" ++ \")\"\n                else if c.inMeta then\n                    Context.crash c \"You need to use full \"\n                else\n                    elixirE c left ++ \".(\" ++ elixirE c right ++ \")\"\n\n            (Access (Variable modules) [ fn ]) :: args ->\n                let\n                    mod =\n                        modulePath modules\n\n                    fnName =\n                        toSnakeCase True fn\n                in\n                    if areMatchingArity c mod fn args then\n                        mod ++ \".\" ++ fnName ++ \"(\" ++ reduceArgs c args \", \" ++ \")\"\n                    else\n                        mod ++ \".\" ++ fnName ++ \"().(\" ++ reduceArgs c args \").(\" ++ \")\"\n\n            _ ->\n                elixirE c left ++ \".(\" ++ elixirE c right ++ \")\"\n\n\nencodeAccessMacroAndRest : Context -> ( Selector.AccessMacro, List Expression ) -> String\nencodeAccessMacroAndRest c ( Selector.AccessMacro t arity selectors, rest ) =\n    let\n        encodeSelector (Selector.Access s) =\n            \":\" ++ toSnakeCase True s\n\n        encodedSelectors =\n            selectors |> List.map encodeSelector |> String.join \", \"\n\n        encodedType =\n            case t of\n                Selector.Update ->\n                    \"update_in_\"\n\n                Selector.Get ->\n                    \"get_in_\"\n\n                Selector.Put ->\n                    \"put_in_\"\n\n        encodedRest =\n            case rest of\n                [] ->\n                    \"\"\n\n                list ->\n                    \".(\"\n                        ++ (List.map (elixirE c) rest |> String.join \").(\")\n                        ++ \")\"\n    in\n        encodedType\n            ++ \"([\"\n            ++ encodedSelectors\n            ++ \"])\"\n            ++ encodedRest\n\n\n{-| Returns code representation of tuple or function depending on definition\n-}\ntupleOrFunction : Context -> Expression -> String\ntupleOrFunction c a =\n    case flattenApplication a of\n        -- Not a macro\n        (Application left right) :: [] ->\n            functionApplication c left right\n\n        -- A macro\n        (Variable [ \"ffi\" ]) :: rest ->\n            Context.crash c \"Ffi inside function body is deprecated since Elchemy 0.3\"\n\n        (Variable [ \"macro\" ]) :: rest ->\n            Context.crash c \"You can't use `macro` inside a function body\"\n\n        (Variable [ \"tryFfi\" ]) :: rest ->\n            Context.crash c \"tryFfi inside function body is deprecated since Elchemy 0.3\"\n\n        (Variable [ \"lffi\" ]) :: rest ->\n            Context.crash c \"Lffi inside function body is deprecated since Elchemy 0.3\"\n\n        (Variable [ \"flambda\" ]) :: rest ->\n            Context.crash c \"Flambda is deprecated since Elchemy 0.3\"\n\n        [ Variable [ \"Just\" ], arg ] ->\n            \"{\" ++ elixirE c arg ++ \"}\"\n\n        [ Variable [ \"Ok\" ], arg ] ->\n            \"{:ok, \" ++ elixirE c arg ++ \"}\"\n\n        [ Variable [ \"Err\" ], arg ] ->\n            \"{:error, \" ++ elixirE c arg ++ \"}\"\n\n        [ Variable [ \"Do\" ], arg ] ->\n            \"quote do \" ++ elixirE c arg ++ \" end\"\n\n        -- Regular non-macro application\n        ((Variable list) as call) :: rest ->\n            Selector.maybeAccessMacro c call rest\n                |> Maybe.map (encodeAccessMacroAndRest c)\n                |> Maybe.withDefault\n                    (Helpers.moduleAccess c.mod list\n                        |> (\\( mod, last ) ->\n                                aliasFor (Context.changeCurrentModule (Context.maybeModuleAlias c mod) c) last rest\n                                    |> Maybe.withDefault\n                                        (\"{\"\n                                            ++ elixirE c (Variable [ last ])\n                                            ++ \", \"\n                                            ++ (List.map (elixirE c) rest |> String.join \", \")\n                                            ++ \"}\"\n                                        )\n                           )\n                    )\n\n        other ->\n            Context.crash c (\"Shouldn't ever work for\" ++ toString other)\n\n\n{-| Return an alias for type alias or union type if it exists, return Nothing otherwise\n-}\naliasFor : Context -> String -> List Expression -> Maybe String\naliasFor c name rest =\n    maybeOr (typeAliasApplication c name rest) (typeApplication c name rest)\n\n\n{-| Returns Just only if the passed alias type is a type alias\n-}\nfilterTypeAlias : Context.Alias -> Maybe Context.Alias\nfilterTypeAlias ({ aliasType } as ali) =\n    case aliasType of\n        Context.TypeAlias ->\n            Just ali\n\n        Context.Type ->\n            Nothing\n\n\n{-| Returns a type alias application based on current context definitions\n-}\ntypeAliasApplication : Context -> String -> List Expression -> Maybe String\ntypeAliasApplication c name args =\n    Context.getAlias c.mod name c\n        |> Maybe.andThen filterTypeAlias\n        |> Maybe.andThen (Type.typeAliasConstructor args)\n        |> Maybe.map (elixirE c)\n\n\n{-| Returns a type application based on current context definitions\n-}\ntypeApplication : Context -> String -> List Expression -> Maybe String\ntypeApplication c name args =\n    Context.getType c.mod name c\n        |> (Maybe.map <|\n                \\{ arity } ->\n                    let\n                        len =\n                            List.length args\n\n                        dif =\n                            arity - len\n\n                        arguments =\n                            generateArguments dif\n\n                        varArgs =\n                            List.map (List.singleton >> Variable) arguments\n                    in\n                        if arity == 0 then\n                            atomize name\n                        else if dif >= 0 then\n                            (arguments\n                                |> List.map ((++) \"fn \")\n                                |> List.map (flip (++) \" -> \")\n                                |> String.join \"\"\n                            )\n                                ++ \"{\"\n                                ++ atomize name\n                                ++ \", \"\n                                ++ (List.map (rememberVariables varArgs c |> elixirE) (args ++ varArgs)\n                                        |> String.join \", \"\n                                   )\n                                ++ \"}\"\n                                |> flip (++) (String.repeat dif \" end\")\n                        else\n                            Context.crash c <|\n                                \"Expected \"\n                                    ++ toString arity\n                                    ++ \" arguments for '\"\n                                    ++ name\n                                    ++ \"'. Got: \"\n                                    ++ toString (List.length args)\n           )\n\n\n{-| Returns True if an expression is type application or false if it's a regular application\n-}\nisTuple : Expression -> Bool\nisTuple a =\n    case a of\n        Application a _ ->\n            isTuple a\n\n        Variable [ \"()\" ] ->\n            True\n\n        Variable [ name ] ->\n            isCapitilzed name\n\n        Variable list ->\n            Helpers.moduleAccess \"\" list\n                |> (\\( _, last ) -> isTuple (Variable [ last ]))\n\n        other ->\n            False\n\n\n{-| Create 'case' expression by passing a value being \"cased on\" and list of branches\n-}\ncaseE : Context -> Expression -> List ( Expression, Expression ) -> String\ncaseE c var body =\n    \"case \"\n        ++ elixirE c var\n        ++ \" do\"\n        ++ String.join \"\" (List.map (rememberVariables [ var ] c |> caseBranch) body)\n        ++ ind c.indent\n        ++ \"end\"\n\n\n{-| Create a single branch of case statement by giving left and right side of the arrow\n-}\ncaseBranch : Context -> ( Expression, Expression ) -> String\ncaseBranch c ( left, right ) =\n    (ind (c.indent + 1) ++ elixirE (inArgs c) left)\n        ++ \" ->\"\n        ++ ind (c.indent + 2)\n        ++ elixirE (c |> indent |> indent |> rememberVariables [ left ]) right\n\n\n{-| Used to encode a function and create a curried function from a lambda expression\n-}\nlambda : Context -> List Expression -> Expression -> String\nlambda c args body =\n    case args of\n        arg :: rest ->\n            \"fn \"\n                ++ elixirE (inArgs c) arg\n                ++ \" -> \"\n                ++ lambda (c |> rememberVariables [ arg ]) rest body\n                ++ \" end\"\n\n        [] ->\n            elixirE c body\n\n\n{-| Produce a variable out of it's expression, considering some of the hardcoded values\nused for easier interaction with Elixir\n-}\nelixirVariable : Context -> List String -> String\nelixirVariable c var =\n    case var of\n        [] ->\n            \"\"\n\n        [ \"()\" ] ->\n            \"{}\"\n\n        [ \"Nothing\" ] ->\n            \"nil\"\n\n        [ \"Just\" ] ->\n            \"fn x1 -> {x1} end\"\n\n        [ \"Err\" ] ->\n            \"fn x1 -> {:error, x1} end\"\n\n        [ \"Ok\" ] ->\n            \"fn x1 -> {:ok, x1} end\"\n\n        [ \"curry\" ] ->\n            \"curried()\"\n\n        [ \"uncurry\" ] ->\n            \"uncurried()\"\n\n        list ->\n            Helpers.moduleAccess c.mod list\n                |> (\\( mod, name ) ->\n                        if isCapitilzed name then\n                            aliasFor (Context.changeCurrentModule mod c) name []\n                                |> Maybe.withDefault (atomize name)\n                        else if String.startsWith \"@\" name then\n                            String.dropLeft 1 name\n                                |> atomize\n                        else\n                            case operatorType name of\n                                Builtin ->\n                                    -- We need a curried version, so kernel won't work\n                                    if name == \"<|\" then\n                                        \"flip().((&|>/0).())\"\n                                    else\n                                        \"(&XBasics.\" ++ translateOperator name ++ \"/0).()\"\n\n                                Custom ->\n                                    translateOperator name\n\n                                None ->\n                                    name |> toSnakeCase True |> Variable.varOrNah c\n                   )\n"
  },
  {
    "path": "src/Elchemy/Ffi.elm",
    "content": "module Elchemy.Ffi exposing (generateFfi)\n\nimport Ast.Expression exposing (Expression(..))\nimport Ast.Statement exposing (Type(TypeConstructor))\nimport Dict\nimport Elchemy.Context as Context exposing (Context, Parser, onlyWithoutFlag)\nimport Elchemy.Function as Function\nimport Elchemy.Helpers as Helpers\n    exposing\n        ( applicationToList\n        , generateArguments\n        , generateArguments_\n        , ind\n        , toSnakeCase\n        )\nimport Elchemy.Type as Type\nimport Elchemy.Variable as Variable exposing (rememberVariables)\n\n\n{-| Encodes and inlines a foreign function interface macro\n-}\ngenerateFfi :\n    Context\n    -> Parser\n    -> String\n    -> List (List Type)\n    -> Expression\n    -> String\ngenerateFfi c elixirE name argTypes e =\n    let\n        typeDef =\n            c.commons.modules\n                |> Dict.get c.mod\n                |> Maybe.andThen (.functions >> Dict.get name)\n\n        appList =\n            applicationToList e\n\n        uncurryArguments c =\n            uncurrify c elixirE argTypes\n\n        wrapAllInVar =\n            List.map <| List.singleton >> Variable\n    in\n        case ( typeDef, applicationToList e ) of\n            ( Nothing, (Variable [ \"ffi\" ]) :: _ ) ->\n                Context.crash c \"Ffi requires type definition\"\n\n            ( Nothing, (Variable [ \"macro\" ]) :: _ ) ->\n                Context.crash c \"Macro requires type definition\"\n\n            ( Just def, [ Variable [ \"ffi\" ], String mod, String fun ] ) ->\n                let\n                    arguments =\n                        generateArguments_ \"a\" def.arity\n                in\n                    Function.functionCurry c elixirE name def.arity []\n                        ++ (onlyWithoutFlag c \"noverify\" name <|\n                                ind c.indent\n                                    ++ \"verify as: \"\n                                    ++ mod\n                                    ++ \".\"\n                                    ++ fun\n                                    ++ \"/\"\n                                    ++ toString def.arity\n                           )\n                        ++ ind c.indent\n                        ++ \"def\"\n                        ++ Function.privateOrPublic c name\n                        ++ \" \"\n                        ++ toSnakeCase True name\n                        ++ \"(\"\n                        ++ (arguments |> String.join \", \")\n                        ++ \")\"\n                        ++ \", do: \"\n                        ++ mod\n                        ++ \".\"\n                        ++ fun\n                        ++ \"(\"\n                        ++ (uncurryArguments (rememberVariables (wrapAllInVar arguments) c) |> String.join \", \")\n                        ++ \")\"\n\n            ( Just def, [ Variable [ \"macro\" ], String mod, String fun ] ) ->\n                let\n                    arguments =\n                        generateArguments_ \"a\" def.arity\n\n                    varArgs =\n                        wrapAllInVar arguments\n                in\n                    if Type.hasReturnedType (TypeConstructor [ \"Macro\" ] []) def.def then\n                        \"defmacro\"\n                            ++ Function.privateOrPublic c name\n                            ++ \" \"\n                            ++ toSnakeCase True name\n                            ++ \"(\"\n                            ++ (arguments |> String.join \", \")\n                            ++ \")\"\n                            ++ \", do: \"\n                            ++ mod\n                            ++ \".\"\n                            ++ fun\n                            ++ \"(\"\n                            ++ (varArgs |> List.map (elixirE (rememberVariables varArgs c)) |> String.join \", \")\n                            ++ \")\"\n                    else\n                        Context.crash c \"Macro calls have to return a Macro type\"\n\n            ( Just def, [ Variable [ \"tryFfi\" ], String mod, String fun ] ) ->\n                let\n                    arguments =\n                        generateArguments_ \"a\" def.arity\n                in\n                    Function.functionCurry c elixirE name def.arity []\n                        ++ ind c.indent\n                        ++ \"def\"\n                        ++ Function.privateOrPublic c name\n                        ++ \" \"\n                        ++ toSnakeCase True name\n                        ++ \"(\"\n                        ++ (generateArguments_ \"a\" def.arity |> String.join \", \")\n                        ++ \")\"\n                        ++ \" do \"\n                        ++ ind (c.indent + 1)\n                        ++ \"try_catch fn -> \"\n                        ++ ind (c.indent + 2)\n                        ++ mod\n                        ++ \".\"\n                        ++ fun\n                        ++ \"(\"\n                        ++ (uncurryArguments (rememberVariables (wrapAllInVar arguments) c) |> String.join \", \")\n                        ++ \")\"\n                        ++ ind (c.indent + 1)\n                        ++ \"end\"\n                        ++ ind c.indent\n                        ++ \"end\"\n\n            _ ->\n                Context.crash c \"Wrong ffi definition\"\n\n\n{-| Walk through function definition and uncurry all of the multi argument functions\n-}\nuncurrify : Context -> Parser -> List (List Type) -> List String\nuncurrify c elixirE argTypes =\n    let\n        arity =\n            List.length argTypes - 1\n\n        indexes =\n            List.range 1 arity\n    in\n        List.map2 (,) indexes argTypes\n            |> List.map\n                (\\( i, arg ) ->\n                    case arg of\n                        [] ->\n                            Context.crash c \"Impossible\"\n\n                        [ any ] ->\n                            \"a\" ++ toString i\n\n                        list ->\n                            let\n                                var =\n                                    Variable [ \"a\" ++ toString i ]\n\n                                makeFlambda =\n                                    Flambda <| List.length list - 1\n                            in\n                                resolveFfi c elixirE (makeFlambda var)\n                )\n\n\ntype Ffi\n    = Lffi Expression Expression\n    | Ffi Expression Expression Expression\n    | TryFfi Expression Expression Expression\n    | Flambda Int Expression\n    | Macro Expression Expression Expression\n\n\n{-| encodes an ffi based on context and a parser\n-}\nresolveFfi : Context -> Parser -> Ffi -> String\nresolveFfi c elixirE ffi =\n    let\n        combineComas args =\n            args |> List.map (elixirE c) |> String.join \",\"\n    in\n        case ffi of\n            TryFfi (String mod) (String fun) (Tuple args) ->\n                \"try_catch fn _ -> \"\n                    ++ mod\n                    ++ \".\"\n                    ++ fun\n                    ++ \"(\"\n                    ++ combineComas args\n                    ++ \")\"\n                    ++ \" end\"\n\n            -- One or many arg fun\n            TryFfi (String mod) (String fun) any ->\n                \"try_catch fn _ -> \"\n                    ++ mod\n                    ++ \".\"\n                    ++ fun\n                    ++ \"(\"\n                    ++ elixirE c any\n                    ++ \")\"\n                    ++ \" end\"\n\n            -- Elchemy hack\n            Ffi (String mod) (String fun) (Tuple args) ->\n                mod ++ \".\" ++ fun ++ \"(\" ++ combineComas args ++ \")\"\n\n            -- One or many arg fun\n            Ffi (String mod) (String fun) any ->\n                mod ++ \".\" ++ fun ++ \"(\" ++ elixirE c any ++ \")\"\n\n            -- Elchemy hack\n            Macro (String mod) (String fun) (Tuple args) ->\n                mod ++ \".\" ++ fun ++ \"(\" ++ combineComas args ++ \")\"\n\n            -- One or many arg fun\n            Macro (String mod) (String fun) any ->\n                mod ++ \".\" ++ fun ++ \"(\" ++ elixirE c any ++ \")\"\n\n            -- Elchemy hack\n            Lffi (String fun) (Tuple args) ->\n                fun ++ \"(\" ++ combineComas args ++ \")\"\n\n            -- One arg fun\n            Lffi (String fun) any ->\n                fun ++ \"(\" ++ elixirE c any ++ \")\"\n\n            Flambda arity fun ->\n                let\n                    args =\n                        generateArguments arity\n                in\n                    \"fn (\"\n                        ++ String.join \",\" args\n                        ++ \") -> \"\n                        ++ elixirE c fun\n                        ++ (List.map (\\a -> \".(\" ++ a ++ \")\") args\n                                |> String.join \"\"\n                           )\n                        ++ \" end\"\n\n            _ ->\n                Context.crash c \"Wrong ffi call\"\n"
  },
  {
    "path": "src/Elchemy/Function.elm",
    "content": "module Elchemy.Function\n    exposing\n        ( functionCurry\n        , genFunctionDefinition\n        , genOverloadedFunctionDefinition\n        , privateOrPublic\n        )\n\nimport Ast.Expression exposing (Expression(..))\nimport Ast.Statement exposing (Type)\nimport Dict\nimport Elchemy.Context as Context exposing (Context, Parser, inArgs, indent)\nimport Elchemy.Helpers as Helpers\n    exposing\n        ( Operator(..)\n        , generateArguments\n        , ind\n        , isCustomOperator\n        , operatorType\n        , toSnakeCase\n        , translateOperator\n        )\nimport Elchemy.Variable as Variable exposing (rememberVariables)\n\n\n{-| Encodes a function defintion with all decorations like curry and type spec\n-}\ngenFunctionDefinition :\n    Context\n    -> Parser\n    -> String\n    -> List Expression\n    -> Expression\n    -> String\ngenFunctionDefinition c elixirE name args body =\n    let\n        typeDef =\n            c.commons.modules\n                |> Dict.get c.mod\n                |> Maybe.andThen (.functions >> Dict.get name)\n\n        arity =\n            typeDef |> Maybe.map .arity |> Maybe.withDefault 0\n\n        lambdasAt =\n            getLambdaArgumentIndexes (Maybe.map .def typeDef)\n    in\n        if Context.hasFlag \"nodef\" name c then\n            functionCurry c elixirE name arity lambdasAt\n        else\n            functionCurry c elixirE name arity lambdasAt\n                ++ genElixirFunc c elixirE name args (arity - List.length args) body\n                ++ \"\\n\"\n\n\n{-| Generates an overloaded function defintion when body is matched on case\n-}\ngenOverloadedFunctionDefinition :\n    Context\n    -> Parser\n    -> String\n    -> List Expression\n    -> Expression\n    -> List ( Expression, Expression )\n    -> String\ngenOverloadedFunctionDefinition c elixirE name args body expressions =\n    let\n        typeDef =\n            c.commons.modules\n                |> Dict.get c.mod\n                |> Maybe.andThen (.functions >> Dict.get name)\n\n        arity =\n            typeDef |> Maybe.map .arity |> Maybe.withDefault 0\n\n        lambdasAt =\n            getLambdaArgumentIndexes (Maybe.map .def typeDef)\n\n        pairAsArgs asArgs =\n            asArgs\n                |> List.map2 (flip <| BinOp <| Variable [ \"as\" ]) args\n\n        caseBranch ( left, right ) =\n            case left of\n                Tuple matchedArgs ->\n                    genElixirFunc c elixirE name (pairAsArgs matchedArgs) (arity - List.length (pairAsArgs matchedArgs)) right\n\n                _ ->\n                    genElixirFunc c elixirE name (pairAsArgs [ left ]) (arity - 1) right\n    in\n        if Context.hasFlag \"nodef\" name c then\n            functionCurry c elixirE name arity lambdasAt\n        else\n            functionCurry c elixirE name arity lambdasAt\n                ++ (expressions\n                        |> List.map caseBranch\n                        |> List.foldr (++) \"\"\n                        |> flip (++) \"\\n\"\n                   )\n\n\n{-| Encodes a function defintion based on given params\n-}\ngenElixirFunc :\n    Context\n    -> Parser\n    -> String\n    -> List Expression\n    -> Int\n    -> Expression\n    -> String\ngenElixirFunc c elixirE name args missingArgs body =\n    case ( operatorType name, args ) of\n        ( Builtin, [ l, r ] ) ->\n            [ ind c.indent\n            , \"def\"\n            , privateOrPublic c name\n            , \" \"\n            , elixirE (c |> rememberVariables [ l ]) l\n            , \" \"\n            , translateOperator name\n            , \" \"\n            , elixirE (rememberVariables [ r ] c) r\n            , \" do\"\n            , ind <| c.indent + 1\n            , elixirE (indent c |> rememberVariables args) body\n            , ind c.indent\n            , \"end\"\n            ]\n                |> String.join \"\"\n\n        ( Custom, _ ) ->\n            [ ind c.indent\n            , \"def\"\n            , privateOrPublic c name\n            , \" \"\n            , translateOperator name\n            , \"(\"\n            , args\n                |> List.map (c |> rememberVariables args |> elixirE)\n                |> flip (++) (generateArguments missingArgs)\n                |> String.join \", \"\n            , \") do\"\n            , ind <| c.indent + 1\n            , elixirE (indent c |> rememberVariables args) body\n            , generateArguments missingArgs\n                |> List.map (\\a -> \".(\" ++ a ++ \")\")\n                |> String.join \"\"\n            , ind c.indent\n            , \"end\"\n            ]\n                |> String.join \"\"\n\n        ( Builtin, _ ) ->\n            Context.crash c\n                (\"operator \" ++ name ++ \" has to have 2 arguments but has \" ++ toString args)\n\n        ( None, _ ) ->\n            let\n                missing =\n                    generateArguments missingArgs\n\n                wrapIfMiss s =\n                    if List.length missing > 0 then\n                        s\n                    else\n                        \"\"\n\n                missingVarargs =\n                    List.map (List.singleton >> Variable) missing\n            in\n                [ ind c.indent\n                , \"def\"\n                , privateOrPublic c name\n                , \" \"\n                , toSnakeCase True name\n                , \"(\"\n                , args\n                    ++ missingVarargs\n                    |> List.map (c |> inArgs |> elixirE)\n                    |> String.join \", \"\n                , \") do\"\n                , ind <| c.indent + 1\n                , wrapIfMiss \"(\"\n                , elixirE (indent c |> rememberVariables (args ++ missingVarargs)) body\n                , wrapIfMiss \")\"\n                , missing\n                    |> List.map (\\a -> \".(\" ++ a ++ \")\")\n                    |> String.join \"\"\n                , ind c.indent\n                , \"end\"\n                ]\n                    |> String.join \"\"\n\n\n{-| Returns \"p\" if a function is private. Else returns empty string\n-}\nprivateOrPublic : Context -> String -> String\nprivateOrPublic context name =\n    if Context.isPrivate context name then\n        \"p\"\n    else\n        \"\"\n\n\n{-| Encodes a curry macro for the function\n-}\nfunctionCurry : Context -> Parser -> String -> Int -> List ( Int, Int ) -> String\nfunctionCurry c elixirE name arity lambdasAt =\n    case ( arity, Context.hasFlag \"nocurry\" name c ) of\n        ( 0, _ ) ->\n            \"\"\n\n        ( _, True ) ->\n            \"\"\n\n        ( arity, False ) ->\n            let\n                resolvedName =\n                    if isCustomOperator name then\n                        translateOperator name\n                    else\n                        toSnakeCase True name\n\n                p =\n                    privateOrPublic c name\n\n                lambdas =\n                    lambdasAt\n                        |> List.map (\\( a, b ) -> \"{\" ++ toString a ++ \", \" ++ toString b ++ \"}\")\n            in\n                if lambdas == [] || p == \"p\" then\n                    [ ind c.indent\n                    , \"curry\"\n                    , \" \"\n                    , resolvedName\n                    , \"/\"\n                    , toString arity\n                    ]\n                        |> String.join \"\"\n                else\n                    [ ind c.indent\n                    , \"curry\"\n                    , \" \"\n                    , resolvedName\n                    , \"/\"\n                    , toString arity\n                    , \", lambdas: [\"\n                    , lambdas |> String.join \", \"\n                    , \"]\"\n                    ]\n                        |> String.join \"\"\n\n\n{-| Gives indexes (starting from 0) of the arguments which\nare lambdas with arity bigger than 1\n-}\ngetLambdaArgumentIndexes : Maybe Type -> List ( Int, Int )\ngetLambdaArgumentIndexes t =\n    Maybe.map Helpers.typeApplicationToList t\n        |> Maybe.withDefault []\n        |> List.map Helpers.typeApplicationToList\n        |> List.indexedMap (,)\n        -- -1 since a -> b is not 2 arity\n        |> List.map (Tuple.mapSecond <| List.length >> (+) -1)\n        |> List.filter (\\( _, r ) -> r > 1)\n"
  },
  {
    "path": "src/Elchemy/Helpers.elm",
    "content": "module Elchemy.Helpers\n    exposing\n        ( (=>)\n        , MaybeUpper(..)\n        , Operator(..)\n        , applicationToList\n        , atomize\n        , capitalize\n        , constructApplication\n        , escape\n        , filterMaybe\n        , findInList\n        , generateArguments\n        , generateArguments_\n        , ind\n        , indAll\n        , indNoNewline\n        , isCapitilzed\n        , isCustomOperator\n        , isStdModule\n        , lastAndRest\n        , listNonEmptyOr\n        , listToApplication\n        , maybeOr\n        , maybeReplaceStd\n        , moduleAccess\n        , modulePath\n        , operatorType\n        , operators\n        , ops\n        , prependAll\n        , replaceOp\n        , replaceOp_\n        , replaceReserved\n        , reservedBasicFunctions\n        , reservedKernelFunctions\n        , reservedWords\n        , toSnakeCase\n        , translateOperator\n        , trimIndentations\n        , typeApplicationToList\n        , uncons\n        , unquoteSplicing\n        )\n\nimport Ast.Expression exposing (Expression(..))\nimport Ast.Statement exposing (Type(..))\nimport Char\nimport Dict exposing (Dict)\nimport Regex exposing (HowMany(..), Regex(..), regex)\n\n\ntype MaybeUpper\n    = Upper String\n    | Lower String\n\n\n{-| Convert string to snakecase, if the flag is set to true then it won't replace reserved words\n-}\ntoSnakeCase : Bool -> String -> String\ntoSnakeCase isntAtom s =\n    let\n        safe x =\n            if isntAtom then\n                replaceReserved x\n            else\n                x\n    in\n        if String.toUpper s == s then\n            String.toLower s\n        else\n            s\n                |> Regex.split Regex.All (Regex.regex \"(?=[A-Z])\")\n                |> String.join \"_\"\n                |> String.toLower\n                |> safe\n\n\ncapitalize : String -> String\ncapitalize s =\n    String.uncons s\n        |> Maybe.map (Tuple.mapFirst Char.toUpper >> uncurry String.cons)\n        |> Maybe.withDefault \"\"\n\n\natomize : String -> String\natomize s =\n    \":\" ++ toSnakeCase False s\n\n\n{-| Returns if string start with uppercase\n-}\nisCapitilzed : String -> Bool\nisCapitilzed s =\n    String.uncons s\n        |> Maybe.map (Tuple.first >> Char.isUpper)\n        |> Maybe.withDefault False\n\n\nindNoNewline : Int -> String\nindNoNewline i =\n    List.repeat ((i + 1) * 2) \" \" |> String.join \"\"\n\n\nind : Int -> String\nind i =\n    \"\\n\" ++ indNoNewline i\n\n\nprependAll : String -> String -> String\nprependAll with target =\n    String.lines target\n        |> List.map\n            (\\line ->\n                if String.trim line == \"\" then\n                    line\n                else\n                    with ++ line\n            )\n        |> String.join \"\\n\"\n\n\nindAll : Int -> String -> String\nindAll i s =\n    \"\\n\" ++ prependAll (String.dropLeft 1 (ind i)) s\n\n\nuncons : List a -> ( Maybe a, List a )\nuncons list =\n    case list of\n        a :: b ->\n            ( Just a, b )\n\n        [] ->\n            ( Nothing, [] )\n\n\nlastAndRest : List a -> ( Maybe a, List a )\nlastAndRest list =\n    list\n        |> List.reverse\n        |> uncons\n        |> Tuple.mapSecond List.reverse\n\n\nmoduleAccess : String -> List String -> ( String, String )\nmoduleAccess defaultModule stringList =\n    stringList\n        |> List.reverse\n        |> uncons\n        |> Tuple.mapSecond (List.reverse >> listNonEmptyOr (String.join \".\") defaultModule)\n        |> Tuple.mapFirst (Maybe.withDefault \"\")\n        |> (\\( a, b ) -> ( b, a ))\n\n\nlistNonEmptyOr : (List a -> b) -> b -> List a -> b\nlistNonEmptyOr f b aList =\n    case aList of\n        [] ->\n            b\n\n        list ->\n            f list\n\n\nunquoteSplicing : String -> String\nunquoteSplicing =\n    Regex.replace All (regex \"(^\\\\{|\\\\}$)\") (\\_ -> \"\")\n\n\noperators : Dict String String\noperators =\n    [ ( \"||\", \"||\" )\n    , ( \"&&\", \"&&\" )\n    , ( \"==\", \"==\" )\n    , ( \"/=\", \"!=\" )\n    , ( \"<\", \"<\" )\n    , ( \">\", \">\" )\n    , ( \">=\", \">=\" )\n    , ( \"<=\", \"<=\" )\n    , ( \"++\", \"++\" )\n    , ( \"+\", \"+\" )\n    , ( \"-\", \"-\" )\n    , ( \"*\", \"*\" )\n    , ( \"/\", \"/\" )\n    , ( \">>\", \">>>\" )\n    , ( \"<|\", \"\" )\n    , ( \"<<\", \"\" )\n    , ( \"|>\", \"|>\" )\n\n    -- Exception\n    , ( \"%\", \"rem\" )\n\n    -- Exception\n    , ( \"//\", \"div\" )\n\n    -- Exception\n    --, ( \"rem\", \"rem\" )\n    -- Exception\n    , ( \"^\", \"\" )\n\n    -- Exception\n    , ( \"::\", \"cons\" )\n    , ( \"not\", \"!\" )\n    , ( \",\", \"tuple2\" )\n    , ( \",,\", \"tuple3\" )\n    , ( \",,,\", \"tuple4\" )\n    , ( \",,,,\", \"tuple5\" )\n    , ( \"as\", \"=\" )\n    ]\n        |> List.foldl (uncurry Dict.insert) Dict.empty\n\n\ntype Operator\n    = None\n    | Builtin\n    | Custom\n\n\nisCustomOperator : String -> Bool\nisCustomOperator op =\n    operatorType op == Custom\n\n\noperatorType : String -> Operator\noperatorType name =\n    let\n        is_builtin =\n            operators\n                |> Dict.keys\n                |> List.any ((==) name)\n\n        is_custom =\n            Regex.contains (regex \"^[+\\\\-\\\\/*=.$<>:&|^?%#@~!]+$\") name\n    in\n        case ( is_builtin, is_custom ) of\n            ( True, _ ) ->\n                Builtin\n\n            ( False, True ) ->\n                Custom\n\n            _ ->\n                None\n\n\ntranslateOperator : String -> String\ntranslateOperator op =\n    case Dict.get op operators of\n        Just \"\" ->\n            Debug.crash <|\n                op\n                    ++ \" is not a valid or not implemented yet operator\"\n\n        Just key ->\n            key\n\n        _ ->\n            replaceOp op\n\n\ntrimIndentations : String -> String\ntrimIndentations line =\n    Regex.replace All (regex \"\\\\s+\\\\n\") (always \"\\n\") line\n\n\ngenerateArguments : Int -> List String\ngenerateArguments =\n    generateArguments_ \"x\"\n\n\ngenerateArguments_ : String -> Int -> List String\ngenerateArguments_ str n =\n    List.range 1 n\n        |> List.map toString\n        |> List.map ((++) str)\n\n\nescape : String -> String\nescape s =\n    Regex.replace All (regex \"\\\\\\\\\") (always \"\\\\\\\\\") s\n\n\nops : List ( Int, Char )\nops =\n    [ '+', '-', '/', '*', '=', '.', '$', '<', '>', ':', '&', '|', '^', '?', '%', '#', '@', '~', '!' ] |> List.indexedMap (,)\n\n\n{-| Gives a String representation of module path\n-}\nmodulePath : List String -> String\nmodulePath list =\n    let\n        snakeIfLower a =\n            if isCapitilzed a then\n                a\n            else\n                toSnakeCase True a\n    in\n        list\n            |> List.map snakeIfLower\n            |> String.join \".\"\n            |> maybeReplaceStd\n\n\nmaybeReplaceStd : String -> String\nmaybeReplaceStd s =\n    if isStdModule s then\n        \"Elchemy.X\" ++ s\n    else\n        s\n\n\nisStdModule : String -> Bool\nisStdModule a =\n    List.member a\n        [ \"Basics\"\n        , \"Bitwise\"\n        , \"Char\"\n        , \"Date\"\n        , \"Debug\"\n        , \"Dict\"\n        , \"List\"\n        , \"String\"\n        , \"Maybe\"\n        , \"Regex\"\n        , \"Result\"\n        , \"Set\"\n        , \"String\"\n        , \"Tuple\"\n        ]\n\n\nreservedWords : List String\nreservedWords =\n    [ \"fn\"\n    , \"do\"\n    , \"end\"\n    , \"cond\"\n    , \"receive\"\n    , \"or\"\n    , \"and\"\n    , \"quote\"\n    , \"unquote\"\n    , \"unquote_splicing\"\n    , \"module\"\n    , \"use\"\n    ]\n\n\nreservedBasicFunctions : List String\nreservedBasicFunctions =\n    [ -- From Elchemy STD\n      \"cons\"\n    , \"compare\"\n    , \"xor\"\n    , \"negate\"\n    , \"sqrt\"\n    , \"clamp\"\n    , \"logBase\"\n    , \"e\"\n    , \"pi\"\n    , \"cos\"\n    , \"sin\"\n    , \"tan\"\n    , \"acos\"\n    , \"asin\"\n    , \"atan\"\n    , \"atan2\"\n    , \"round\"\n    , \"floor\"\n    , \"ceiling\"\n    , \"truncate\"\n    , \"toFloat\"\n    , \"toString\"\n    , \"identity\"\n    , \"always\"\n    , \"flip\"\n    , \"tuple2\"\n    , \"tuple3\"\n    , \"tuple4\"\n    , \"tuple5\"\n    , \"rec\"\n    ]\n\n\nreservedKernelFunctions : List String\nreservedKernelFunctions =\n    [ -- From Elixir std\n      \"isTuple\"\n    , \"abs\"\n    , \"apply\"\n    , \"binary_part\"\n    , \"bit_size\"\n    , \"byte_size\"\n    , \"div\"\n    , \"elem\"\n    , \"exit\"\n    , \"function_exported?\"\n    , \"get_and_update_in\"\n    , \"get_in\"\n    , \"hd\"\n    , \"inspect\"\n    , \"is_atom\"\n    , \"is_binary\"\n    , \"is_bitstring\"\n    , \"is_boolean\"\n    , \"is_float\"\n    , \"is_function\"\n    , \"is_integer\"\n    , \"is_list\"\n    , \"is_map\"\n    , \"is_number\"\n    , \"is_pid\"\n    , \"is_port\"\n    , \"is_reference\"\n    , \"is_tuple\"\n    , \"length\"\n    , \"macro_exported?\"\n    , \"make_ref\"\n    , \"map_size\"\n    , \"max\"\n    , \"min\"\n    , \"node\"\n    , \"not\"\n    , \"pop_in\"\n    , \"put_elem\"\n    , \"put_in\"\n    , \"rem\"\n    , \"round\"\n    , \"self\"\n    , \"send\"\n    , \"spawn\"\n    , \"spawn_link\"\n    , \"spawn_monitor\"\n    , \"struct\"\n    , \"struct!\"\n    , \"throw\"\n    , \"tl\"\n    , \"trunc\"\n    , \"tuple_size\"\n    , \"update_in\"\n    ]\n\n\nreplaceOp : String -> String\nreplaceOp op =\n    String.toList op\n        |> List.map replaceOp_\n        |> String.join \"\"\n        |> flip (++) \"__\"\n\n\nreplaceOp_ : Char -> String\nreplaceOp_ op =\n    case\n        List.filter (\\( i, o ) -> op == o) ops\n    of\n        ( index, _ ) :: _ ->\n            \"op\" ++ toString index\n\n        _ ->\n            Debug.crash \"Illegal op\"\n\n\nreplaceReserved : String -> String\nreplaceReserved a =\n    if List.member a reservedWords then\n        a ++ \"__\"\n    else\n        a\n\n\n{-| Change application into a list of expressions\n-}\napplicationToList : Expression -> List Expression\napplicationToList application =\n    case application of\n        Application left right ->\n            applicationToList left ++ [ right ]\n\n        other ->\n            [ other ]\n\n\n{-| Change list of expressions into an application\n-}\nlistToApplication : List Expression -> Expression\nlistToApplication list =\n    case list of\n        [] ->\n            Debug.crash \"Empty list to expression conversion\"\n\n        [ one ] ->\n            one\n\n        left :: rest ->\n            Application left (listToApplication rest)\n\n\n{-| Change type application into a list of expressions\n-}\ntypeApplicationToList : Type -> List Type\ntypeApplicationToList application =\n    case application of\n        TypeApplication left right ->\n            left :: typeApplicationToList right\n\n        other ->\n            [ other ]\n\n\n{-| Construct application, rever of applicationToList function\n-}\nconstructApplication : List String -> List Expression\nconstructApplication list =\n    case list of\n        [] ->\n            Debug.crash \"Wrong application\"\n\n        [ one ] ->\n            [ Variable [ one ] ]\n\n        head :: tail ->\n            [ List.foldl (\\a acc -> Application acc (Variable [ a ])) (Variable [ head ]) tail ]\n\n\n{-| Nicer syntax for tuples\n-}\n(=>) : a -> b -> ( a, b )\n(=>) =\n    (,)\ninfixr 0 =>\n\n\n{-| Take left maybe, or right maybe if Nothing\n-}\nmaybeOr : Maybe a -> Maybe a -> Maybe a\nmaybeOr m1 m2 =\n    case m1 of\n        Just a ->\n            m1\n\n        Nothing ->\n            m2\n\n\n{-| Filter Maybe based on a predicate\n-}\nfilterMaybe : (a -> Bool) -> Maybe a -> Maybe a\nfilterMaybe f m =\n    flip Maybe.andThen m <|\n        \\a ->\n            if f a then\n                Just a\n            else\n                Nothing\n\n\n{-| Finds a value in a list\n-}\nfindInList : (a -> Bool) -> List a -> Maybe a\nfindInList f =\n    flip List.foldl Nothing <|\n        \\a acc ->\n            if f a then\n                Just a\n            else\n                acc\n"
  },
  {
    "path": "src/Elchemy/Meta.elm",
    "content": "module Elchemy.Meta exposing (metaDefinition)\n\n{-| Defines a meta module for macro interactions\n-}\n\nimport Ast.Expression exposing (Expression(..))\nimport Dict\nimport Elchemy.Ast as Ast\nimport Elchemy.Context as Context exposing (Context)\nimport Elchemy.Expression as Expression\nimport Elchemy.Helpers as Helpers exposing (ind, modulePath)\n\n\ntype ImportOrRequire\n    = Import String String Int\n    | Require String\n\n\n{-| Defines the meta module for Macro usage\n-}\nmetaDefinition : Context -> String\nmetaDefinition c =\n    let\n        defMeta meta =\n            \"defmodule \"\n                ++ c.mod\n                ++ \".Meta do\"\n                ++ ind c.indent\n                ++ requiredImports\n                ++ \"\\n\"\n                ++ ind c.indent\n                ++ Expression.elixirE c meta\n                ++ \"\\nend\"\n\n        getUsedFunctions =\n            Ast.walkExpressionOutwards\n\n        addMacro t acc =\n            case t of\n                Variable [ name ] ->\n                    c.importedFunctions\n                        |> Dict.get name\n                        |> Maybe.map (\\( mod, arity ) -> [ Import mod name arity ])\n                        |> Maybe.withDefault []\n                        |> (++) acc\n\n                Access (Variable mods) _ ->\n                    Require (modulePath mods) :: acc\n\n                _ ->\n                    acc\n\n        requiredImports =\n            c.meta\n                |> Maybe.map (Ast.foldExpression addMacro [])\n                |> Maybe.withDefault []\n                |> List.foldl insertRequirement Dict.empty\n                |> Dict.toList\n                |> List.map\n                    (\\( k, v ) ->\n                        case v of\n                            [] ->\n                                \"require \" ++ k\n\n                            other ->\n                                \"import \"\n                                    ++ k\n                                    ++ \", only: [\"\n                                    ++ (List.map stringify other |> String.join \",\")\n                                    ++ \"]\"\n                    )\n                |> String.join (ind c.indent)\n\n        stringify ( name, arity ) =\n            \"{:\" ++ name ++ \", \" ++ toString arity ++ \"}\"\n\n        insertRequirement rOrI dict =\n            case rOrI of\n                Require mod ->\n                    dict\n                        |> Dict.update mod (Maybe.withDefault [] >> Just)\n\n                Import mod name arity ->\n                    dict\n                        |> Dict.update mod\n                            (Maybe.map ((::) ( name, arity ))\n                                >> Maybe.withDefault [ ( name, arity ) ]\n                                >> Just\n                            )\n    in\n        c.meta\n            |> Maybe.map defMeta\n            |> Maybe.withDefault \"\"\n"
  },
  {
    "path": "src/Elchemy/Operator.elm",
    "content": "module Elchemy.Operator exposing (elixirBinop)\n\nimport Ast.Expression exposing (Expression(..))\nimport Elchemy.Context as Context exposing (Context, Parser)\nimport Elchemy.Helpers as Helpers exposing (Operator(..), ind, operatorType, translateOperator)\n\n\n{-| Encode binary operator inlcuding the researved ones\n-}\nelixirBinop : Context -> Parser -> String -> Expression -> Expression -> String\nelixirBinop c elixirE op l r =\n    case op of\n        \"//\" ->\n            \"div(\" ++ elixirE c l ++ \", \" ++ elixirE c r ++ \")\"\n\n        \"%\" ->\n            \"rem(\" ++ elixirE c l ++ \", \" ++ elixirE c r ++ \")\"\n\n        \"^\" ->\n            \":math.pow(\" ++ elixirE c l ++ \", \" ++ elixirE c r ++ \")\"\n\n        \"::\" ->\n            \"[\"\n                ++ elixirE c l\n                ++ \" | \"\n                ++ elixirE c r\n                ++ \"]\"\n\n        \"<<\" ->\n            elixirBinop c elixirE \">>\" r l\n\n        \"<|\" ->\n            if l == Variable [ \"Do\" ] then\n                \"quote do \" ++ elixirE c r ++ \" end\"\n            else\n                elixirBinop c elixirE \"|>\" r l\n\n        \"|>\" ->\n            \"(\"\n                ++ elixirE c l\n                ++ (flattenPipes r\n                        |> List.map (elixirE c)\n                        |> List.map ((++) (ind c.indent ++ \"|> (\"))\n                        |> List.map (flip (++) \").()\")\n                        |> String.join \"\"\n                   )\n                ++ \")\"\n\n        \"as\" ->\n            elixirE c l\n                ++ \" = \"\n                ++ elixirE c r\n\n        op ->\n            case operatorType op of\n                Builtin ->\n                    [ \"(\", elixirE c l, \" \", translateOperator op, \" \", elixirE c r, \")\" ]\n                        |> String.join \"\"\n\n                Custom ->\n                    translateOperator op\n                        ++ \"(\"\n                        ++ elixirE c l\n                        ++ \", \"\n                        ++ elixirE c r\n                        ++ \")\"\n\n                None ->\n                    Context.crash c (\"Illegal operator \" ++ op)\n\n\n{-| Flattens pipes into a list of expressions\n-}\nflattenPipes : Expression -> List Expression\nflattenPipes e =\n    case e of\n        BinOp (Variable [ \"|>\" ]) l ((BinOp (Variable [ \"|>\" ]) r _) as n) ->\n            [ l ] ++ flattenPipes n\n\n        BinOp (Variable [ \"|>\" ]) l r ->\n            [ l ] ++ [ r ]\n\n        other ->\n            [ other ]\n"
  },
  {
    "path": "src/Elchemy/Selector.elm",
    "content": "module Elchemy.Selector exposing (AccessMacro(..), AccessMacroType(..), Selector(..), maybeAccessMacro)\n\nimport Ast.Expression exposing (Expression(AccessFunction, Application, Variable))\nimport Char\nimport Elchemy.Context as Context exposing (Context)\nimport Elchemy.Helpers as Helpers\nimport List.Extra\nimport Regex\n\n\ntype Selector\n    = Access String\n\n\ntype AccessMacroType\n    = Get\n    | Put\n    | Update\n\n\ntype AccessMacro\n    = AccessMacro AccessMacroType Int (List Selector)\n\n\ngetSelector : Context -> Expression -> Selector\ngetSelector c expression =\n    case expression of\n        AccessFunction name ->\n            Access (Helpers.toSnakeCase True name)\n\n        _ ->\n            Context.crash c \"The only allowed selectors are: .field\"\n\n\nmaybeAccessMacro : Context -> Expression -> List Expression -> Maybe ( AccessMacro, List Expression )\nmaybeAccessMacro c call args =\n    let\n        accessMacroArgs arity args =\n            case compare (List.length args) arity of\n                LT ->\n                    Context.crash c <|\n                        \"Access macros [updateIn/getIn/putIn] cannot be partially applied. Expecting \"\n                            ++ toString arity\n                            ++ \" selector arguments.\"\n\n                EQ ->\n                    ( List.map (getSelector c) args, [] )\n\n                GT ->\n                    List.Extra.splitAt arity args\n                        |> Tuple.mapFirst (List.map <| getSelector c)\n    in\n        case ( call, args ) of\n            ( Variable [ name ], args ) ->\n                accessMacroType name\n                    |> Maybe.map\n                        (\\( t, arity ) ->\n                            let\n                                ( selectors, rest ) =\n                                    accessMacroArgs arity args\n                            in\n                                ( AccessMacro t arity selectors, rest )\n                        )\n\n            _ ->\n                Nothing\n\n\naccessMacroType : String -> Maybe ( AccessMacroType, Int )\naccessMacroType string =\n    let\n        getArity =\n            String.filter Char.isDigit\n                >> String.toInt\n                >> Result.withDefault 1\n\n        getType x =\n            [ ( \"updateIn\\\\d?\", Update )\n            , ( \"putIn\\\\d?\", Put )\n            , ( \"getIn\\\\d?\", Get )\n            ]\n                |> List.foldl\n                    (\\( match, res ) acc ->\n                        case acc of\n                            Nothing ->\n                                if Regex.contains (Regex.regex match) x then\n                                    Just res\n                                else\n                                    Nothing\n\n                            res ->\n                                res\n                    )\n                    Nothing\n    in\n        getType string\n            |> Maybe.map (\\t -> ( t, getArity string ))\n"
  },
  {
    "path": "src/Elchemy/Statement.elm",
    "content": "module Elchemy.Statement exposing (elixirS, moduleStatement)\n\nimport Ast\nimport Ast.BinOp exposing (operators)\nimport Ast.Expression exposing (Expression(..))\nimport Ast.Statement exposing (ExportSet(..), Statement(..), Type(..))\nimport Dict exposing (Dict)\nimport Elchemy.Alias as Alias\nimport Elchemy.Context as Context exposing (Context, deindent, indent, onlyWithoutFlag)\nimport Elchemy.Expression as Expression\nimport Elchemy.Ffi as Ffi\nimport Elchemy.Function as Function\nimport Elchemy.Helpers as Helpers\n    exposing\n        ( (=>)\n        , Operator(..)\n        , filterMaybe\n        , ind\n        , indAll\n        , indNoNewline\n        , isCustomOperator\n        , modulePath\n        , operatorType\n        , prependAll\n        , toSnakeCase\n        , translateOperator\n        , typeApplicationToList\n        )\nimport Elchemy.Type as Type\nimport Regex exposing (HowMany(..), Regex, regex)\n\n\ntype ElchemyComment\n    = Doc String\n    | Ex String\n    | Normal String\n    | Flag String\n\n\ntype DocType\n    = Fundoc\n    | Typedoc\n    | ModuleDoc\n\n\n{-| Make sure first statement is a module declaration\n-}\nmoduleStatement : Statement -> Context\nmoduleStatement s =\n    case s of\n        ModuleDeclaration path exports ->\n            Context.empty (modulePath path) exports\n\n        other ->\n            Debug.crash \"First statement must be module declaration\"\n\n\ntypeDefinition : Context -> String -> List Type -> List Type -> Bool -> ( Context, String )\ntypeDefinition c name args types isUnion =\n    let\n        ( newC, code ) =\n            c.lastDoc\n                |> Maybe.map (elixirDoc c Typedoc name)\n                |> Maybe.withDefault ( c, \"\" )\n\n        getVariableName t =\n            case t of\n                TypeVariable name ->\n                    name\n\n                _ ->\n                    Context.crash c (toString t ++ \" is not a type variable\")\n\n        arguments =\n            if args == [] then\n                \"\"\n            else\n                \"(\"\n                    ++ (List.map getVariableName args |> String.join \", \")\n                    ++ \")\"\n\n        mapType =\n            (if isUnion then\n                Type.uniontype { c | inTypeDefiniton = True }\n             else\n                Type.elixirT False { c | inTypeDefiniton = True }\n            )\n                << Alias.replaceTypeAliases c\n    in\n        (,) newC <|\n            onlyWithoutFlag c \"notype\" name <|\n                code\n                    ++ ind c.indent\n                    ++ \"@type \"\n                    ++ toSnakeCase True name\n                    ++ arguments\n                    ++ \" :: \"\n                    ++ (List.map mapType types |> String.join \" | \")\n                    ++ \"\\n\"\n\n\n{-| Encode any statement\n-}\nelixirS : Context -> Statement -> ( Context, String )\nelixirS c s =\n    case s of\n        InfixDeclaration _ _ _ ->\n            ( c, \"\" )\n\n        TypeDeclaration (TypeConstructor [ name ] args) types ->\n            typeDefinition c name args types True\n\n        TypeAliasDeclaration (TypeConstructor [ name ] args) t ->\n            typeDefinition c name args [ t ] False\n\n        FunctionTypeDeclaration \"meta\" t ->\n            if t == TypeConstructor [ \"List\" ] [ TypeConstructor [ \"Macro\" ] [] ] then\n                ( c, \"\" )\n            else\n                Context.crash c \"Function `meta` is reserved and its type has to be of List Macro\"\n\n        FunctionDeclaration \"meta\" [] body ->\n            if not <| definitionExists \"meta\" c then\n                Context.crash c \"Function `meta` requires type definition of List Macro\"\n            else\n                ( { c | meta = Just body }, \"\" )\n\n        FunctionTypeDeclaration name typedef ->\n            ( c, \"\" )\n\n        FunctionDeclaration name args body ->\n            let\n                definition =\n                    c.commons.modules\n                        |> Dict.get c.mod\n                        |> Maybe.andThen (.functions >> Dict.get name >> Maybe.map .def)\n                        |> Maybe.map (Alias.replaceTypeAliases c)\n\n                ( newC, code ) =\n                    c.lastDoc\n                        |> Maybe.map (elixirDoc c Fundoc name)\n                        |> Maybe.withDefault ( c, \"\" )\n\n                spec =\n                    onlyWithoutFlag newC \"nodef\" name code\n                        ++ (case operatorType name of\n                                Builtin ->\n                                    -- TODO implement operator specs\n                                    \"\"\n\n                                Custom ->\n                                    definition\n                                        |> Maybe.map\n                                            (\\def ->\n                                                onlyWithoutFlag newC \"nospec\" name <|\n                                                    ind newC.indent\n                                                        ++ \"@spec \"\n                                                        ++ translateOperator name\n                                                        ++ Type.typespec newC def\n                                            )\n                                        |> Maybe.withDefault \"\"\n\n                                None ->\n                                    definition\n                                        |> Maybe.map\n                                            (\\def ->\n                                                onlyWithoutFlag newC \"nospec\" name <|\n                                                    ind newC.indent\n                                                        ++ \"@spec \"\n                                                        ++ toSnakeCase True name\n                                                        ++ Type.typespec newC def\n                                            )\n                                        |> Maybe.withDefault \"\"\n                           )\n\n                genFfi =\n                    Ffi.generateFfi c Expression.elixirE name <|\n                        (c.commons.modules\n                            |> Dict.get c.mod\n                            |> Maybe.andThen (.functions >> Dict.get name)\n                            |> Maybe.map (.def >> typeApplicationToList)\n                            |> Maybe.withDefault []\n                            |> List.map typeApplicationToList\n                        )\n\n                isPrivate =\n                    Context.isPrivate c name\n\n                isTuple t =\n                    case t of\n                        Tuple _ ->\n                            True\n\n                        _ ->\n                            False\n            in\n                newC\n                    => (case body of\n                            (Application (Application (Variable [ \"ffi\" ]) _) _) as app ->\n                                spec\n                                    ++ ind (c.indent + 1)\n                                    ++ genFfi app\n\n                            (Application (Application (Variable [ \"tryFfi\" ]) _) _) as app ->\n                                spec\n                                    ++ ind (c.indent + 1)\n                                    ++ genFfi app\n\n                            (Application (Application (Variable [ \"macro\" ]) _) _) as app ->\n                                ind c.indent\n                                    ++ genFfi app\n                                    ++ \"\\n\"\n\n                            -- Case ((Variable [ _ ]) as var) expressions ->\n                            --     if [ var ] == args then\n                            --         Function.genOverloadedFunctionDefinition c Expression.elixirE name args body expressions\n                            --     else\n                            --         Function.genFunctionDefinition c Expression.elixirE name args body\n                            --\n                            -- Case (Tuple vars) expressions ->\n                            --     if vars == args && List.all (Tuple.first >> isTuple) expressions then\n                            --         Function.genOverloadedFunctionDefinition c Expression.elixirE name args body expressions\n                            --     else\n                            --         Function.genFunctionDefinition c Expression.elixirE name args body\n                            _ ->\n                                spec\n                                    ++ Function.genFunctionDefinition c Expression.elixirE name args body\n                       )\n\n        Comment content ->\n            elixirComment c content\n\n        -- That's not a real import. In elixir it's called alias\n        ImportStatement path aliasedAs Nothing ->\n            (c |> Context.addModuleAlias (modulePath path) aliasedAs)\n                => ind c.indent\n                ++ \"alias \"\n                ++ modulePath path\n                ++ aliasAs aliasedAs\n\n        ImportStatement path aliasedAs (Just ((SubsetExport exports) as subset)) ->\n            let\n                mod =\n                    modulePath path\n\n                imports =\n                    List.map exportSetToList exports\n                        |> List.foldr (++) []\n\n                excepts =\n                    c.commons.modules\n                        |> Dict.get c.mod\n                        |> Maybe.map (.functions >> Dict.keys >> duplicates imports)\n                        |> Maybe.withDefault []\n\n                only =\n                    if imports == [] then\n                        []\n                    else\n                        [ \"only: [\"\n                            ++ String.join \", \" (elixirExportList c mod imports)\n                            ++ \"]\"\n                        ]\n\n                except =\n                    if excepts == [] then\n                        []\n                    else\n                        [ \"except: [\"\n                            ++ String.join \", \" (elixirExportList c mod excepts)\n                            ++ \"]\"\n                        ]\n\n                importOrAlias =\n                    if imports == [] && excepts == [] then\n                        \"alias \"\n                    else\n                        \"import \"\n\n                newC =\n                    c\n                        |> Context.addModuleAlias mod aliasedAs\n                        |> insertImports mod subset\n                        |> Context.mergeTypes subset (modulePath path)\n            in\n                newC\n                    => ind newC.indent\n                    ++ importOrAlias\n                    ++ ([ [ modulePath path ], only, except ]\n                            |> List.foldr (++) []\n                            |> String.join \", \"\n                       )\n                    ++ aliasAs aliasedAs\n\n        -- Suppresses the compiler warning\n        ImportStatement [ \"Elchemy\" ] Nothing (Just AllExport) ->\n            ( c, \"\" )\n\n        ImportStatement modPath aliasedAs (Just AllExport) ->\n            let\n                mod =\n                    modulePath modPath\n\n                exports =\n                    c.commons.modules\n                        |> Dict.get mod\n                        |> Maybe.map (.functions >> Dict.keys)\n                        |> Maybe.withDefault []\n\n                excepts =\n                    c.commons.modules\n                        |> Dict.get c.mod\n                        |> Maybe.map (.functions >> Dict.keys >> duplicates exports)\n                        |> Maybe.withDefault []\n\n                except =\n                    if excepts == [] then\n                        []\n                    else\n                        [ \"except: [\"\n                            ++ String.join \", \" (elixirExportList c mod excepts)\n                            ++ \"]\"\n                        ]\n\n                newC =\n                    c\n                        |> Context.addModuleAlias mod aliasedAs\n                        |> insertImports mod AllExport\n                        |> Context.mergeTypes AllExport mod\n            in\n                newC\n                    => ind c.indent\n                    ++ \"import \"\n                    ++ ([ [ mod ], except ]\n                            |> List.foldr (++) []\n                            |> String.join \", \"\n                       )\n                    ++ aliasAs aliasedAs\n\n        s ->\n            (,) c <|\n                Context.notImplemented c \"statement\" s\n\n\n{-| Returns a String \"as: ModuleAlias\" or empty string if no module alias\n-}\naliasAs : Maybe String -> String\naliasAs =\n    Maybe.map (\\newName -> \", as: \" ++ newName)\n        >> Maybe.withDefault \"\"\n\n\n{-| Returns True if\n-}\ndefinitionExists : String -> Context -> Bool\ndefinitionExists name c =\n    c.commons.modules\n        |> Dict.get c.mod\n        |> Maybe.andThen (.functions >> Dict.get name)\n        |> (/=) Nothing\n\n\n{-| Based on ExportSet of the `import` call inserts all of the imported types\nand functions into the current context\n-}\ninsertImports : String -> ExportSet -> Context -> Context\ninsertImports mod subset c =\n    let\n        exportNames =\n            Type.getExportedTypeNames c mod subset\n\n        importedFunctions subset =\n            case subset of\n                AllExport ->\n                    c.commons.modules\n                        |> Dict.get mod\n                        |> Maybe.map .functions\n                        |> Maybe.map Dict.toList\n                        |> Maybe.withDefault []\n                        |> List.map (\\( key, { arity } ) -> ( key, arity ))\n\n                SubsetExport list ->\n                    List.concatMap importedFunctions list\n\n                FunctionExport name ->\n                    c.commons.modules\n                        |> Dict.get mod\n                        |> Maybe.map .functions\n                        |> Maybe.andThen (Dict.get name)\n                        |> Maybe.map (\\{ arity } -> [ ( name, arity ) ])\n                        |> Maybe.withDefault []\n\n                TypeExport _ _ ->\n                    []\n    in\n        { c\n            | importedTypes = List.foldl (flip Dict.insert mod) c.importedTypes exportNames\n            , importedFunctions =\n                importedFunctions subset\n                    |> List.foldl (\\( f, arity ) acc -> Dict.insert f ( mod, arity ) acc) c.importedFunctions\n        }\n\n\n{-| Verify correct flag format\n-}\nverifyFlag : Context -> List String -> Maybe ( String, String )\nverifyFlag c flag =\n    case flag of\n        [ k, v ] ->\n            Just ( k, v )\n\n        [ \"\" ] ->\n            Nothing\n\n        a ->\n            Context.crash c <| \"Wrong flag format \" ++ toString a\n\n\n{-| Encode elixir comment and return a context with updated last doc\n-}\nelixirComment : Context -> String -> ( Context, String )\nelixirComment c content =\n    case getCommentType content of\n        Doc content ->\n            if c.hasModuleDoc then\n                { c | lastDoc = Just content } => \"\"\n            else\n                elixirDoc c ModuleDoc c.mod content\n\n        Ex content ->\n            (,) c <|\n                (content\n                    |> String.split \"\\n\"\n                    |> List.map (Regex.replace All (regex \"^   \") (always \"\"))\n                    -- |> List.map String.trim\n                    |> String.join \"\\n\"\n                    |> indAll c.indent\n                )\n\n        Flag content ->\n            flip (,) \"\" <|\n                (content\n                    |> Regex.split All (regex \"\\\\s+\")\n                    |> List.map (String.split \":+\")\n                    |> List.filterMap (verifyFlag c)\n                    |> List.foldl Context.addFlag c\n                )\n\n        Normal content ->\n            (,) c <|\n                (content\n                    |> prependAll \"# \"\n                    |> indAll c.indent\n                )\n\n\n{-| Enocode a doc and return new context\n-}\nelixirDoc : Context -> DocType -> String -> String -> ( Context, String )\nelixirDoc c doctype name content =\n    let\n        prefix =\n            if not c.hasModuleDoc then\n                \"@moduledoc\"\n            else if doctype == Fundoc then\n                \"@doc\"\n            else\n                \"@typedoc\"\n    in\n        (,)\n            { c\n                | hasModuleDoc = True\n                , lastDoc = Nothing\n            }\n        <|\n            ind c.indent\n                ++ prefix\n                ++ \" \\\"\\\"\\\"\\n \"\n                ++ (content\n                        |> String.lines\n                        |> List.map (maybeDoctest c name)\n                        |> List.map Helpers.escape\n                        |> List.map (Regex.replace All (regex \"\\\"\\\"\\\"\") (always \"\\\\\\\"\\\\\\\"\\\\\\\"\"))\n                        -- |> map trimIndentations\n                        |> String.join (ind c.indent)\n                        -- Drop an unnecessary ammounts of \\n's\n                        |> Regex.replace All (regex \"\\n(\\n| ){3,}\\n\") (always \"\\n\\n\")\n                   )\n                ++ ind c.indent\n                ++ \"\\\"\\\"\\\"\"\n\n\n{-| Get a type of the comment by it's content\n-}\ngetCommentType : String -> ElchemyComment\ngetCommentType comment =\n    let\n        findCommentType regex commentType acc =\n            case acc of\n                Normal content ->\n                    if Regex.contains regex content then\n                        commentType <|\n                            Regex.replace (Regex.AtMost 1) regex (always \"\") content\n                    else\n                        Normal content\n\n                other ->\n                    other\n    in\n        [ ( \"^\\\\sex\\\\b\", Ex )\n        , ( \"^\\\\|\", Doc )\n        , ( \"^\\\\sflag\\\\b\", Flag )\n        ]\n            |> List.map (\\( a, b ) -> ( Regex.regex a, b ))\n            |> List.foldl (uncurry findCommentType) (Normal comment)\n\n\n{-| Encode all exports from a module\n-}\nexportSetToList : ExportSet -> List String\nexportSetToList exp =\n    case exp of\n        TypeExport _ _ ->\n            []\n\n        FunctionExport name ->\n            [ name ]\n\n        AllExport ->\n            []\n\n        SubsetExport _ ->\n            []\n\n\nelixirExportList : Context -> String -> List String -> List String\nelixirExportList c mod list =\n    let\n        defineFor name arity =\n            \"{:'\"\n                ++ name\n                ++ \"', \"\n                ++ toString arity\n                ++ \"}\"\n\n        wrap name =\n            if isCustomOperator name then\n                defineFor (translateOperator name) 0\n                    ++ \", \"\n                    ++ defineFor (translateOperator name) 2\n            else if name == \"ffi\" then\n                \"\"\n            else\n                defineFor (toSnakeCase True name) 0\n                    ++ (c.commons.modules\n                            |> Dict.get mod\n                            |> Maybe.map .functions\n                            |> Maybe.andThen (Dict.get name)\n                            |> Maybe.map .arity\n                            |> filterMaybe ((/=) 0)\n                            |> Maybe.map (defineFor (toSnakeCase True name))\n                            |> Maybe.map ((++) \", \")\n                            |> Maybe.withDefault \"\"\n                       )\n    in\n        List.map wrap list\n\n\nduplicates : List a -> List a -> List a\nduplicates listA listB =\n    List.filter (flip List.member listB) listA\n\n\n{-| Replace a function doc with a doctest if in correct format\n-}\nmaybeDoctest : Context -> String -> String -> String\nmaybeDoctest c forName line =\n    if String.startsWith (ind (c.indent + 1)) (\"\\n\" ++ line) then\n        case Ast.parseExpression Ast.BinOp.operators (String.trim line) of\n            Ok ( _, _, BinOp (Variable [ \"==\" ]) l r ) ->\n                let\n                    shadowed =\n                        Context.getShadowedFunctions c Helpers.reservedBasicFunctions\n                            ++ Context.getShadowedFunctions c Helpers.reservedKernelFunctions\n                            |> List.filter (Tuple.first >> (==) forName)\n\n                    importBasics =\n                        if shadowed == [] then\n                            \"\"\n                        else\n                            Context.importBasicsWithoutShadowed c\n                                |> String.trimRight\n                                |> String.split \"\\n\"\n                                |> String.join (ind (c.indent + 2) ++ \"iex> \")\n                                |> (++) (indNoNewline 1 ++ \"iex> \")\n                                |> flip (++) (ind 0)\n                in\n                    importBasics\n                        ++ indNoNewline (c.indent + 1)\n                        ++ \"iex> import \"\n                        ++ c.mod\n                        ++ ind (c.indent + 2)\n                        ++ \"iex> \"\n                        ++ Expression.elixirE c l\n                        ++ ind (c.indent + 2)\n                        ++ Expression.elixirE c r\n                        ++ \"\\n\"\n\n            _ ->\n                line\n    else\n        line\n"
  },
  {
    "path": "src/Elchemy/Type.elm",
    "content": "module Elchemy.Type exposing (elixirT, getExportedTypeNames, hasReturnedType, typeAliasConstructor, typespec, uniontype)\n\nimport Ast.Expression exposing (Expression(..))\nimport Ast.Statement exposing (ExportSet(..), Type(..))\nimport Dict\nimport Elchemy.Alias as Alias\nimport Elchemy.Context as Context exposing (Context, indent)\nimport Elchemy.Helpers as Helpers\n    exposing\n        ( atomize\n        , filterMaybe\n        , ind\n        , lastAndRest\n        , toSnakeCase\n        , typeApplicationToList\n        )\n\n\n{-| Enocde any elm type\n-}\nelixirT : Bool -> Context -> Type -> String\nelixirT flatten c t =\n    case t of\n        TypeTuple [] ->\n            \"no_return\"\n\n        TypeTuple [ a ] ->\n            elixirT flatten c a\n\n        TypeTuple ((a :: rest) as list) ->\n            \"{\"\n                ++ (List.map (elixirT flatten c) list |> String.join \", \")\n                ++ \"}\"\n\n        TypeVariable \"number\" ->\n            \"number\"\n\n        (TypeVariable name) as var ->\n            case String.uncons name of\n                Just ( '@', name ) ->\n                    toSnakeCase True name\n\n                any ->\n                    if c.inTypeDefiniton then\n                        name\n                    else\n                        \"any\"\n\n        TypeConstructor t args ->\n            let\n                ( mod, last ) =\n                    Helpers.moduleAccess c.mod t\n\n                modulePath =\n                    if mod == c.mod then\n                        c.importedTypes\n                            |> Dict.get last\n                            |> Maybe.map (\\a -> a ++ \".\")\n                            |> Maybe.withDefault \"\"\n                    else\n                        mod ++ \".\"\n            in\n                modulePath ++ elixirType flatten c last args\n\n        TypeRecord fields ->\n            \"%{\"\n                ++ ind (c.indent + 1)\n                ++ (fields\n                        |> List.map (\\( k, v ) -> toSnakeCase False k ++ \": \" ++ elixirT flatten (indent c) v)\n                        |> String.join (\",\" ++ ind (c.indent + 1))\n                   )\n                ++ ind c.indent\n                ++ \"}\"\n\n        (TypeRecordConstructor _ _) as tr ->\n            \"%{\"\n                ++ ind (c.indent + 1)\n                ++ (typeRecordFields (indent c) flatten tr\n                        |> String.join (\", \" ++ ind (c.indent + 1))\n                   )\n                ++ ind c.indent\n                ++ \"}\"\n\n        TypeApplication l r ->\n            if flatten then\n                typeApplicationToList r\n                    |> lastAndRest\n                    |> (\\( last, rest ) ->\n                            \"(\"\n                                ++ ((l :: rest)\n                                        |> List.map (elixirT flatten (indent c))\n                                        |> String.join \", \"\n                                   )\n                                ++ \" -> \"\n                                ++ (last\n                                        |> Maybe.map (elixirT flatten c)\n                                        |> Maybe.withDefault \"\"\n                                   )\n                                ++ \")\"\n                       )\n            else\n                \"(\"\n                    ++ elixirT flatten c l\n                    ++ \" -> \"\n                    ++ elixirT flatten c r\n                    ++ \")\"\n\n\n{-| alias for elixirT with flatting of type application\n-}\nelixirTFlat : Context -> Type -> String\nelixirTFlat =\n    elixirT True\n\n\n{-| alias for elixirT without flatting of type application\n-}\nelixirTNoFlat : Context -> Type -> String\nelixirTNoFlat =\n    elixirT False\n\n\n{-| Return fieilds of type record as a list of string key value pairs\n-}\ntypeRecordFields : Context -> Bool -> Type -> List String\ntypeRecordFields c flatten t =\n    let\n        keyValuePair ( k, v ) =\n            k ++ \": \" ++ elixirT flatten c v\n    in\n        case t of\n            TypeRecordConstructor (TypeConstructor [ name ] args) fields ->\n                let\n                    inherited =\n                        Context.getAlias c.mod name c\n                            |> Maybe.map (\\{ typeBody } -> Alias.resolveTypeBody c typeBody args)\n                            |> Maybe.map (typeRecordFields c flatten)\n                in\n                    List.map keyValuePair fields\n                        ++ Maybe.withDefault [ \"\" ] inherited\n\n            TypeRecordConstructor (TypeRecord inherited) fields ->\n                List.map keyValuePair <| fields ++ inherited\n\n            TypeRecordConstructor (TypeVariable _) fields ->\n                List.map keyValuePair fields\n\n            TypeRecordConstructor (TypeTuple [ a ]) fields ->\n                typeRecordFields c flatten (TypeRecordConstructor a fields)\n\n            TypeRecordConstructor ((TypeRecordConstructor _ _) as tr) fields ->\n                List.map keyValuePair fields\n                    ++ typeRecordFields c flatten tr\n\n            (TypeRecord fields) as tr ->\n                List.map keyValuePair fields\n\n            any ->\n                Context.crash c (\"Wrong type record constructor \" ++ toString any)\n\n\n{-| Translate and encode Elm type to Elixir type\n-}\nelixirType : Bool -> Context -> String -> List Type -> String\nelixirType flatten c name args =\n    case ( name, args ) of\n        ( \"String\", [] ) ->\n            \"String.t\"\n\n        ( \"Char\", [] ) ->\n            \"integer\"\n\n        ( \"Bool\", [] ) ->\n            \"boolean\"\n\n        ( \"Int\", [] ) ->\n            \"integer\"\n\n        ( \"Pid\", [] ) ->\n            \"pid\"\n\n        ( \"Float\", [] ) ->\n            \"float\"\n\n        ( \"List\", [ t ] ) ->\n            \"list(\" ++ elixirT flatten c t ++ \")\"\n\n        -- ( \"Dict\", [ key, val ] ) ->\n        --     \"%{}\"\n        ( \"Maybe\", [ t ] ) ->\n            \"{\" ++ elixirT flatten c t ++ \"} | nil\"\n\n        ( \"Nothing\", [] ) ->\n            \"nil\"\n\n        ( \"Just\", [ t ] ) ->\n            elixirT flatten c t\n\n        ( \"Err\", [ t ] ) ->\n            \"{:error, \" ++ elixirT flatten c t ++ \"}\"\n\n        ( \"Ok\", [ t ] ) ->\n            if t == TypeTuple [] then\n                \"ok\"\n            else\n                \"{:ok,\" ++ elixirT flatten c t ++ \"}\"\n\n        ( t, [] ) ->\n            toSnakeCase True t\n\n        -- aliasOr c t [] (atomize t)\n        ( t, list ) ->\n            toSnakeCase True t\n                ++ \"(\"\n                ++ (List.map (elixirT flatten c) list |> String.join \", \")\n                ++ \")\"\n\n\n\n-- aliasOr c t list <|\n--     \"{\"\n--         ++ atomize t\n--         ++ \", \"\n--         ++ (List.map (elixirT flatten c) list |> String.join \", \")\n--         ++ \"}\"\n\n\n{-| Gets all types from a subset export\n-}\ngetExportedTypeNames : Context -> String -> ExportSet -> List String\ngetExportedTypeNames c mod subset =\n    case subset of\n        SubsetExport list ->\n            List.concatMap (getExportedTypeNames c mod) list\n\n        TypeExport name _ ->\n            [ name ]\n\n        AllExport ->\n            c.commons.modules\n                |> Dict.get mod\n                |> Maybe.map (\\mod -> (mod.aliases |> Dict.keys) ++ (mod.types |> Dict.keys))\n                |> Maybe.withDefault []\n\n        FunctionExport _ ->\n            []\n\n\n{-| Enocde a typespec with 0 arity\n-}\ntypespec0 : Context -> Type -> String\ntypespec0 c t =\n    \"() :: \" ++ elixirTNoFlat c t\n\n\n{-| Encode a typespec\n-}\ntypespec : Context -> Type -> String\ntypespec c t =\n    case t |> typeApplicationToList |> lastAndRest of\n        ( Just last, args ) ->\n            \"(\"\n                ++ (List.map (elixirTNoFlat c) args\n                        |> String.join \", \"\n                   )\n                ++ \") :: \"\n                ++ elixirTNoFlat c last\n\n        ( Nothing, _ ) ->\n            Context.crash c \"impossible\"\n\n\n{-| Encode a union type\n-}\nuniontype : Context -> Type -> String\nuniontype c t =\n    case t of\n        TypeConstructor [ name ] [] ->\n            atomize name\n\n        TypeConstructor [ name ] list ->\n            \"{\"\n                ++ atomize name\n                ++ \", \"\n                ++ (List.map (elixirTNoFlat c) list |> String.join \", \")\n                ++ \"}\"\n\n        other ->\n            Context.crash c (\"I am looking for union type constructor. But got \" ++ toString other)\n\n\n{-| Change a constructor of a type alias into an expression after resolving it from contextual alias\n-}\ntypeAliasConstructor : List Expression -> Context.Alias -> Maybe Expression\ntypeAliasConstructor args ({ parentModule, aliasType, arity, body, typeBody } as ali) =\n    case ( aliasType, body ) of\n        ( Context.Type, _ ) ->\n            Nothing\n\n        ( _, TypeConstructor [ name ] _ ) ->\n            Nothing\n\n        ( _, TypeRecord kvs ) ->\n            let\n                params =\n                    List.length kvs\n                        |> (+) (0 - List.length args)\n                        |> List.range 1\n                        |> List.map (toString >> (++) \"arg\")\n                        |> List.map (List.singleton >> Variable)\n\n                varargs =\n                    kvs\n                        |> List.map2 (flip (,)) (args ++ params)\n                        |> List.map (Tuple.mapFirst Tuple.first)\n            in\n                Record varargs\n                    |> Lambda params\n                    |> Just\n\n        -- Error in AST. Single TypeTuple are just paren app\n        ( _, TypeTuple [ app ] ) ->\n            typeAliasConstructor args { ali | typeBody = Context.SimpleType app }\n\n        ( _, TypeTuple kvs ) ->\n            let\n                args =\n                    List.length kvs\n                        |> List.range 1\n                        |> List.map (toString >> (++) \"arg\")\n                        |> List.map (List.singleton >> Variable)\n            in\n                Just (Lambda args (Tuple args))\n\n        ( _, TypeVariable name ) ->\n            Just (Variable [ name ])\n\n        other ->\n            Nothing\n\n\n{-| Apply alias, orelse return the provided default value\n-}\naliasOr : Context -> String -> List Type -> String -> String\naliasOr c name args default =\n    Context.getAlias c.mod name c\n        |> (Maybe.map <|\n                \\{ parentModule, typeBody, aliasType } ->\n                    if parentModule == c.mod then\n                        elixirTNoFlat c (Alias.resolveTypeBody c typeBody args)\n                    else\n                        case aliasType of\n                            Context.Type ->\n                                parentModule ++ \".\" ++ elixirTNoFlat c (Alias.resolveTypeBody c typeBody args)\n\n                            Context.TypeAlias ->\n                                Alias.resolveTypeBody c typeBody args\n                                    |> elixirTNoFlat { c | mod = parentModule }\n           )\n        |> Maybe.withDefault default\n\n\nhasReturnedType : Type -> Type -> Bool\nhasReturnedType returned t =\n    case List.reverse (typeApplicationToList t) of\n        [] ->\n            False\n\n        t :: _ ->\n            t == returned\n"
  },
  {
    "path": "src/Elchemy/Variable.elm",
    "content": "module Elchemy.Variable\n    exposing\n        ( extractName\n        , groupByCrossDependency\n        , organizeLetInVariablesOrder\n        , rememberVariables\n        , varOrNah\n        )\n\nimport Ast.Expression exposing (..)\nimport Elchemy.Context as Context exposing (Context, inArgs)\nimport Elchemy.Helpers as Helpers exposing (toSnakeCase)\nimport List.Extra\nimport Set\n\n\n{-| Put variables into context so they are treated like variables in future\n-}\nrememberVariables : List Expression -> Context -> Context\nrememberVariables list c =\n    let\n        addToContext var context =\n            { context\n                | variables = Set.insert (toSnakeCase True var) context.variables\n            }\n    in\n        list\n            |> List.map extractVariablesUsed\n            |> List.foldr (++) []\n            |> List.foldl addToContext c\n\n\n{-| Check if a string is a variable or no, based on remembered variables\n-}\nvarOrNah : Context -> String -> String\nvarOrNah c var =\n    if Set.member var c.variables || c.inArgs then\n        var\n    else if c.inMeta then\n        c.mod ++ \".\" ++ var ++ \"()\"\n    else\n        var ++ \"()\"\n\n\n{-| Extract variables from an expression\n-}\nextractVariablesUsed : Expression -> List String\nextractVariablesUsed exp =\n    let\n        many vars =\n            vars\n                |> List.map extractVariablesUsed\n                |> List.foldr (++) []\n\n        one var =\n            [ var ]\n\n        none =\n            []\n    in\n        case exp of\n            Record vars ->\n                vars\n                    |> List.map Tuple.second\n                    |> many\n\n            Tuple vars ->\n                many vars\n\n            Variable [ name ] ->\n                one name\n\n            List vars ->\n                many vars\n\n            Application left right ->\n                many [ left, right ]\n\n            BinOp (Variable [ \"::\" ]) x xs ->\n                many [ x, xs ]\n\n            BinOp (Variable [ \"as\" ]) ((Variable _) as v1) ((Variable _) as v2) ->\n                many [ v1, v2 ]\n\n            BinOp (Variable [ \"as\" ]) l ((Variable [ _ ]) as r) ->\n                many [ l, r ]\n\n            BinOp _ l r ->\n                many [ l, r ]\n\n            -- Assignments\n            Case head branches ->\n                List.concatMap (uncurry rightWithoutLeft) branches\n                    |> withoutVars (extractVariablesUsed head)\n\n            Let definitions return ->\n                List.concatMap (uncurry rightWithoutLeft) definitions\n\n            Lambda head body ->\n                extractVariablesUsed body\n                    |> withoutVars (List.concatMap extractVariablesUsed head)\n\n            _ ->\n                none\n\n\n{-| Organize let in variables in order based on how they use each other\nExample:\na = b\nb = 1\nWould become:\nb = 1\na = b\n-}\norganizeLetInVariablesOrder : Context -> List ( Expression, Expression ) -> List ( Expression, Expression )\norganizeLetInVariablesOrder c expressionList =\n    case bubbleSelect (\\a b -> not <| isIn a b) expressionList of\n        Ok list ->\n            list\n\n        Err list ->\n            let\n                _ =\n                    Context.crash c <|\n                        \"Couldn't find a solution to \"\n                            ++ toString (list |> List.map Tuple.first)\n            in\n                []\n\n\n{-| Returns a name of a variable, or a name of a function being applied\n-}\nextractName : Context -> Expression -> String\nextractName c expression =\n    case Helpers.applicationToList expression of\n        [ Variable [ name ] ] ->\n            name\n\n        [ single ] ->\n            Context.crash c (toString single ++ \" is not a variable\")\n\n        multi ->\n            List.head multi\n                |> Maybe.map (extractName c)\n                |> Maybe.withDefault \"\"\n\n\n{-| Returns a list of names of a variable, or a name of a function being applied\n\na = 1 --> [\"a\"]\nf a b c = 1 --> [\"f\"]\n(a, b, c) = 1 --> [\"a\", \"b\", \"c\"]\n\n-}\nextractNamesAssigned : Expression -> List String\nextractNamesAssigned expression =\n    case Helpers.applicationToList expression of\n        [ Variable [ name ] ] ->\n            [ name ]\n\n        [ single ] ->\n            extractVariablesUsed single\n\n        multi ->\n            List.head multi\n                |> Maybe.map extractNamesAssigned\n                |> Maybe.withDefault []\n\n\n{-| Extracts only the arguments of an expression (if the expression is a function)\n-}\nextractArguments : Expression -> List String\nextractArguments expression =\n    case Helpers.applicationToList expression of\n        [ single ] ->\n            []\n\n        multi ->\n            List.tail multi\n                |> Maybe.map (List.concatMap extractNamesAssigned)\n                |> Maybe.withDefault []\n\n\n{-| Returns true if a name of right argument is mentioned in a body of left variable\n-}\nisIn : ( Expression, Expression ) -> ( Expression, Expression ) -> Bool\nisIn ( leftHead, _ ) ( rightHead, rightDef ) =\n    let\n        anyMembers members list =\n            List.any (flip List.member list) members\n    in\n        withoutVars (extractArguments rightHead) (extractVariablesUsed rightDef)\n            |> anyMembers (extractNamesAssigned leftHead)\n\n\n{-| Returns a list of variables in right, without these passed as first argument}\n-}\nwithoutVars : List String -> List String -> List String\nwithoutVars vars right =\n    List.filter (not << flip List.member vars) right\n\n\n{-| Returns a list of variables used in right expression, without variables defined in\nleft expression\n-}\nrightWithoutLeft : Expression -> Expression -> List String\nrightWithoutLeft left right =\n    withoutVars (extractVariablesUsed left) (extractVariablesUsed right)\n\n\n{-| Groups functions that mutually call each other in lists\n-}\ngroupByCrossDependency : List ( Expression, Expression ) -> List (List ( Expression, Expression ))\ngroupByCrossDependency expressionsList =\n    expressionsList\n        |> List.Extra.groupWhile (\\l r -> isIn l r && isIn r l)\n\n\n{-| Selects a correct order of elements in a list based on a dependency algorithm\nif dependency requirement (f) is met for all of the other elements it is inserted\notherwise it looks for next element that fits the requirement.\nFunction returns first combination found, satifying the predicate.\nIf no function was found it returns Nothing\n-}\nbubbleSelect : (a -> a -> Bool) -> List a -> Result (List a) (List a)\nbubbleSelect f list =\n    let\n        findIndex discarded list =\n            List.Extra.break (\\a -> List.all (f a) discarded) list\n\n        findNext discarded list acc =\n            case list of\n                [] ->\n                    if discarded == [] then\n                        Ok <| List.reverse acc\n                    else\n                        Err discarded\n\n                -- Trick to allow mutual recursion\n                -- case findIndex discarded acc of\n                --     ( l, r ) ->\n                --         Ok <| l ++ (List.reverse discarded) ++ r\n                current :: tail ->\n                    let\n                        newlist =\n                            discarded ++ tail\n                    in\n                        if List.all (flip f current) newlist then\n                            findNext [] newlist (current :: acc)\n                        else\n                            findNext (current :: discarded) tail acc\n    in\n        findNext [] list []\n"
  },
  {
    "path": "templates/Hello.elm",
    "content": "module Hello exposing (..)\n\n{-| Example module, It says hello if you ask it nicely\n-}\n\n\n{-| Prints \"world!\"\n\n    hello == \"world!\"\n\n-}\nhello : String\nhello =\n    \"world!\"\n"
  },
  {
    "path": "templates/elchemy.exs",
    "content": "defmodule ElchemyInit do\n\n  @deps_directory_depth 3\n\n  def init(project) do\n    if !project || !project[:deps] do\n      IO.warn \"\"\"\n        The project structure is invalid. Make sure that\n\n          |> elem(Code.eval_file(\".elchemy.exs\"), 0).init\n\n        Line was put __after__ the closing bracked `]`\n      \"\"\"\n    else\n      project\n      |> put_in([:compilers], [:elchemy | (project[:compilers] || Mix.compilers())])\n      |> put_in([:elchemy_path], \"elm\")\n      |> put_in([:deps], project[:deps] ++ elm_deps())\n    end\n  end\n\n  def elm_deps() do\n    if File.exists?(\"elm-deps\") do\n        find!(\"elm-deps\", @deps_directory_depth)\n        |> check_mix_file()\n        |> Enum.map(fn {app_name, path} ->\n            {app_name, path: path, override: true}\n        end)\n    else\n        []\n    end\n  end\n\n  def check_mix_file(paths) do\n    Enum.map paths, fn path ->\n      mix_file = Path.join(path, \"mix.exs\")\n      if File.exists?(mix_file) do\n        {parse_app_name(mix_file), path}\n      else\n        {app_name, version} = app_info_from_path(path)\n        create_mix_file(mix_file, app_name, version)\n        {app_name, path}\n      end\n    end\n  end\n\n  def create_mix_file(mix_file, app_name, version) do\n    module_name = app_name\n    |> Atom.to_string\n    |> String.split(\"_\")\n    |> Enum.map(&String.capitalize/1)\n    |> Enum.join(\"\")\n\n    content =\n      \"\"\"\n      defmodule #{module_name}.Mixfile do\n        use Mix.Project\n\n        def project do\n          [app: #{inspect app_name},\n           version: \"#{version}\",\n           elixir: \"~> 1.4\",\n           build_embedded: Mix.env == :prod,\n           start_permanent: Mix.env == :prod,\n           elixirc_paths: [\"src\"],\n           deps: deps()]\n        end\n\n        def application do\n          [extra_applications: [:logger]]\n        end\n\n        defp deps, do: [{:elchemy, override: false}]\n      end\n      \"\"\"\n    IO.puts \"Creating mix file #{mix_file}\"\n\n    File.write!(mix_file, content)\n  end\n\n  def app_info_from_path(path) do\n    [_, _, repo_name, version] = path |> Path.split\n\n    app_name = repo_name\n    |> String.replace(~r\"[-]\", \"_\")\n    |> String.replace(~r\"[^a-zA-Z0-9_]\", \"\")\n    |> String.to_atom\n\n    {app_name, version}\n  end\n\n  def find!(dir, depth), do: find!([], dir, depth)\n  def find!(dirs, dir, 0), do: [dir | dirs]\n  def find!(dirs, dir, depth) do\n    dir\n    |> File.ls!\n    |> Enum.map(&Path.join(dir, &1))\n    |> Enum.filter(&File.dir?/1)\n    |> Enum.reduce(dirs, &find!(&2, &1, depth - 1))\n  end\n\n  def parse_app_name(mix_file) do\n    contents = File.read!(mix_file)\n    {app_name, _} = ~r\"app:(.*?),\" |> Regex.run(contents, capture: :all_but_first)\n    |> List.first |> String.trim |> Code.eval_string\n    app_name\n  end\nend\n\nElchemyInit\n"
  },
  {
    "path": "templates/elchemy_test.exs",
    "content": "defmodule ElchemyTest do\n  use ExUnit.Case\n  use Elchemy\n  doctest Hello\n\n  test \"Hello\" do\n    assert Hello.hello() == \"world!\"\n  end\n\nend\n"
  },
  {
    "path": "templates/elm-package.json",
    "content": "{\n    \"version\": \"1.0.0\",\n    \"summary\": \"helpful summary of your project, less than 80 characters\",\n    \"repository\": \"https://github.com/user/project.git\",\n    \"license\": \"BSD3\",\n    \"source-directories\": [\n        \"./elm\"\n    ],\n    \"exposed-modules\": [],\n    \"dependencies\": {\n        \"elm-lang/core\": \"5.1.1 <= v < 6.0.0\",\n        \"wende/elchemy-core\": \"0.0.0 <= v < 0.8.8\"\n    },\n    \"elm-version\": \"0.18.0 <= v < 0.19.0\"\n}\n"
  },
  {
    "path": "tests/.gitignore",
    "content": "/elm-stuff/\n"
  },
  {
    "path": "tests/Main.elm",
    "content": "port module Main exposing (..)\n\nimport Test\nimport Tests\nimport UnitTests\nimport Test.Runner.Node exposing (run, TestProgram)\nimport Json.Encode exposing (Value)\n\n\nmain : TestProgram\nmain =\n    run emit (Test.describe \"Elchemy\" [ Tests.all, UnitTests.all ])\n\n\nport emit : ( String, Value ) -> Cmd msg\n"
  },
  {
    "path": "tests/Tests.elm",
    "content": "module Tests exposing (accessMacros, all, binOps, caseOfs, doctests, fileImports, functions, has, hasFull, letIns, lists, records, specs, tuples, typeAliases, typeConstructors, types)\n\nimport Elchemy.Compiler as Compiler\nimport Expect\nimport Regex exposing (..)\nimport String\nimport Test exposing (..)\n\n\n(|++) : String -> String -> String\n(|++) l r =\n    l ++ \"\\n\" ++ r\n\n\nhasFull expected s =\n    let\n        result =\n            Compiler.tree s\n    in\n        String.contains (String.trim expected) result\n            |> Expect.true (\"Code:\\n\" ++ result ++ \"\\n\\ndoes not contain:\\n\" ++ expected)\n\n\nhas : String -> String -> Expect.Expectation\nhas expected s =\n    let\n        result =\n            Compiler.tree (\"module MyModule exposing (nothing) \\n{-| Moduledoc -}\" ++ s)\n                |> Regex.replace All (regex \"\\\\n( )+\") (always \"\")\n                |> Regex.replace All (regex \"( )+\") (always \" \")\n    in\n        String.contains (String.trim expected) result\n            |> Expect.true (\"Code:\\n\" ++ result ++ \"\\n\\ndoes not contain:\\n\" ++ expected)\n\n\ntuples : Test\ntuples =\n    describe \"Tuples\"\n        [ test \"Tuples w spaces\" <|\n            \\() ->\n                \"tuple = (1, 2)\" |> has \"{1, 2}\"\n        , test \"Tuples w/o spaces\" <|\n            \\() ->\n                \"tuple = ( 1, 2 )\" |> has \"{1, 2}\"\n        , test \"Nested tuples\" <|\n            \\() ->\n                \"tuple = (1, (2, 3))\" |> has \"{1, {2, 3}}\"\n        ]\n\n\nlists : Test\nlists =\n    describe \"Lists\"\n        [ test \"Lists w spaces\" <|\n            \\() ->\n                \"list = [ 1, 2 ]\" |> has \"[1, 2]\"\n        , test \"Lists w/o spaces\" <|\n            \\() ->\n                \"list = [1, 2]\" |> has \"[1, 2]\"\n        , test \"Nested Lists\" <|\n            \\() ->\n                \"list = [ 1, [2, 3] ]\" |> has \"[1, [2, 3]]\"\n        , test \"Other nested list\" <|\n            \\() ->\n                \"list = [[1, 2], 3]\" |> has \"[[1, 2], 3]\"\n        , test \"Cons operator\" <|\n            \\() ->\n                \"list = 1 :: 2 :: [3]\" |> has \"[1 | [2 | [3]]]\"\n        ]\n\n\nfunctions : Test\nfunctions =\n    let\n        testModules =\n            \"\"\"\n>>>> b.elm\nmodule B exposing (..)\n\nimport A exposing (..)\n\ntestFull : Int\ntestFull = A.fun 1 2\n\ntestCurried : Int\ntestCurried = A.fun 1\n\njoin : List String -> String\njoin a = String.join \" \" a\n\ntested : Float\ntested = importedFun 10 10.0\n\n>>>> a.elm\nmodule A exposing (fun, importedFun)\nfun : Int -> Int -> Int\nfun a b = 1\n\nimportedFun : Int -> Float -> Float\nimportedFun a b = 1\n\"\"\"\n    in\n        describe \"Functions\"\n            [ test \"Application\" <|\n                \\() ->\n                    \"app = a b c d\" |> has \"a().(b()).(c()).(d())\"\n            , test \"Uncurried application when all args provided\" <|\n                \\() ->\n                    \"a : a -> a -> a -> a\"\n                        |++ \"app = a b c d\"\n                        |> has \"a(b(), c(), d())\"\n            , test \"ffi\" <|\n                \\() ->\n                    \"upcase : String -> String\"\n                        |++ \"upcase name = ffi \\\"String\\\" \\\"to_upper\\\" \"\n                        |> has \"String.to_upper(\"\n            , test \"macro\" <|\n                \\() ->\n                    \"upcase : Macro\"\n                        |++ \"upcase = macro \\\"String\\\" \\\"to_upper\\\" \"\n                        |> has \"String.to_upper(\"\n            , test \"macro doesn't lambdify arguments\" <|\n                \\() ->\n                    \"upcase : (Int -> Int) -> Macro\"\n                        |++ \"upcase = macro \\\"String\\\" \\\"to_upper\\\" \"\n                        |> has \"String.to_upper(a1)\"\n            , test \"Function names are snakecased\" <|\n                \\() ->\n                    \"camelCase = 1\" |> has \"camel_case()\"\n            , test \"Function calls are snakecased\" <|\n                \\() ->\n                    \"a = camelCase 1\" |> has \"camel_case().(1)\"\n            , test \"Uncurried function calls are snakecased\" <|\n                \\() ->\n                    \"fooBar : a -> a -> a\"\n                        |++ \"app = fooBar 1 2\"\n                        |> has \"foo_bar(1, 2)\"\n            , test \"Can call function recursively\" <|\n                \\() ->\n                    \"a = let f a = f (a - 1) in f\"\n                        |> has \"f = rec f, fn a ->\"\n            , test \"Correct curried application from modules\" <|\n                \\() -> testModules |> hasFull \"A.fun().(1)\"\n            , test \"Correct full application from modules\" <|\n                \\() -> testModules |> hasFull \"A.fun(1, 2)\"\n            , test \"Correct curried application for undefined module\" <|\n                \\() -> testModules |> hasFull \"Elchemy.XString.join().(\\\" \\\").(a)\"\n            , test \"Correct curried application for imported functions\" <|\n                \\() -> testModules |> hasFull \"imported_fun(10, 10.0)\"\n            ]\n\n\nbinOps : Test\nbinOps =\n    describe \"Binary Operators\"\n        [ test \"Simple ops\" <|\n            \\() ->\n                \"add = a + b\" |> has \"a() + b()\"\n        , test \"Ops as lambda\" <|\n            \\() ->\n                \"add = (+)\" |> has \"(&XBasics.+/0).()\"\n        , test \"Ops as lambda with param\" <|\n            \\() ->\n                \"add = ((+) 2)\" |> has \"(&XBasics.+/0).().(2)\"\n        , test \"Complex ops as lambda \" <|\n            \\() ->\n                \"add = map (+) list\" |> has \"map().((&XBasics.+/0).()).(list())\"\n        ]\n\n\nspecs : Test\nspecs =\n    describe \"Specs\"\n        [ test \"Typespecs with dependant types\" <|\n            \\() ->\n                \"sum : (List Int) -> Int\"\n                    |++ \"sum = 0\"\n                    |> has \"@spec sum(list(integer)) :: integer\"\n        , test \"Typespecs with functions\" <|\n            \\() ->\n                \"map : (List a) -> (a -> a) -> (List a)\"\n                    |++ \"map = 0\"\n                    |> has \"map(list(any), (any -> any)) :: list(any)\"\n        , test \"Typespecs with functions #2\" <|\n            \\() ->\n                \"map : (a -> a) -> (b -> b) -> (List a)\"\n                    |++ \"map = 0\"\n                    |> has \"map((any -> any), (any -> any)) :: list(any)\"\n        , test \"Typespecs with multiple arg functions\" <|\n            \\() ->\n                \"map : (List a) -> (a -> a -> b) -> (List a)\"\n                    |++ \"map = 0\"\n                    |> has \"map(list(any), (any -> (any -> any))) :: list(any) \"\n        , test \"Typespecs names are snakecased\" <|\n            \\() ->\n                \"mapMap : a\"\n                    |++ \"mapMap = 0\"\n                    |> has \"@spec map_map\"\n        , test \"Records in typespecs\" <|\n            \\() ->\n                \"record : { a : Int, b : String}\"\n                    |++ \"record = 0\"\n                    |> has \"@spec record() :: %{a: integer,b: String.t}\"\n        , test \"Remote typespecs\" <|\n            \\() ->\n                \"f : Remote.Module.Type -> String.T\"\n                    |++ \"f = 0\"\n                    |> has \"f(Remote.Module.type) :: String.t\"\n        ]\n\n\nrecords : Test\nrecords =\n    describe \"Records\"\n        [ test \"Records work\" <|\n            \\() ->\n                \"a = { a = 1 }\" |> has \"%{a: 1}\"\n        , test \"Complex records work\" <|\n            \\() ->\n                \"a = { a = 1, b = 2, c = (a b)}\" |> has \"%{a: 1, b: 2, c: a().(b())}\"\n        , test \"Updating records work\" <|\n            \\() ->\n                \"addToA r = {r | a = (r.a + 5), b = 2} \" |> has \"%{r | a: (r.a + 5), b: 2}\"\n        ]\n\n\ntypes : Test\ntypes =\n    describe \"types\"\n        [ test \"Types\" <|\n            \\() ->\n                \"type AType = BType | CType\" |> has \"@type a_type :: :b_type | :c_type\"\n        , test \"TypeRecord\" <|\n            \\() ->\n                \"type alias A = {a : Int, b: Int, c: Int}\"\n                    |++ \"a = A 1 2 3\"\n                    |> has \"%{a: 1, b: 2, c: 3}\"\n        , test \"Type alias application\" <|\n            \\() ->\n                \"type alias A = {a : Int, b : Int}\"\n                    |++ \"a = A 10\"\n                    |> has \"fn arg1 -> %{a: 10, b: arg1} end\"\n        , test \"Types work when applied incompletely\" <|\n            \\() ->\n                \"type Focus = A Int Int | B Int Int Int\"\n                    |++ \"a = B 1 1\"\n                    |> has \"fn x1 -> {:b, 1, 1, x1} end\"\n        , test \"TypeTuple\" <|\n            \\() ->\n                \"type alias A = (Int, Int, Int)\"\n                    |++ \"a = A 1 2 \"\n                    |> has \"{arg1, arg2, arg3}\"\n        , test \"Types ignore typealiases\" <|\n            \\() ->\n                \"type alias AnyAlias = Lol\"\n                    |++ \"type AnyType = AnyAlias | AnyType\"\n                    |> has \"@type any_type :: :any_alias | :any_type\"\n        , test \"Types can wrap records\" <|\n            \\() ->\n                \"type Lens big small = Lens { get : big -> small }\"\n                    |> has \"@type lens(big, small) :: {:lens, %{get: (big -> small)}}\"\n        , test \"Types args don't polute type application\" <|\n            \\() ->\n                \"type Focus big small = Focus { get : big -> small }\"\n                    |++ \"a = Focus { get = get, update = update }\"\n                    |> has \"{:focus, %{get: get(), update: update()}}\"\n        ]\n\n\ntypeConstructors : Test\ntypeConstructors =\n    describe \"Type Constructors\"\n        [ test \"Type application\" <|\n            \\() ->\n                \"a = Type a b c\" |> has \"{:type, a(), b(), c()}\"\n        , test \"Type in tuple\" <|\n            \\() ->\n                \"a = (Type, a, b, c)\" |> has \"{:type, a(), b(), c()}\"\n        , test \"Remote types\" <|\n            \\() ->\n                \"a = Remote.Type a b c\" |> has \"{:type, a(), b(), c()}\"\n        , test \"Remote types in tuples\" <|\n            \\() ->\n                \"a = (Remote.Type, a, b, c)\" |> has \"{:type, a(), b(), c()}\"\n        ]\n\n\ndoctests : Test\ndoctests =\n    describe \"Doctests\"\n        [ test \"Doctests\" <|\n            \\() ->\n                \"{-| A equals 1. It just does\\n\"\n                    ++ \"    a == 1\\n\"\n                    ++ \"-}\\n\"\n                    ++ \"a : Int\\n\"\n                    ++ \"a = 1\\n\"\n                    |> has \"iex> a\\n\"\n        ]\n\n\ntypeAliases : Test\ntypeAliases =\n    describe \"Type aliases in specs\"\n        [ test \"TypeAlias substitution\" <|\n            \\() ->\n                \"type alias MyType a = List a\"\n                    |++ \"test : MyType Int\"\n                    |++ \"test = 0\"\n                    |> has \"@spec test() :: my_type(integer\"\n        , test \"Type substitution\" <|\n            \\() ->\n                \"type MyType = Wende | NieWende\"\n                    |++ \"test : MyType\"\n                    |++ \"test = 0\"\n                    |> has \"@spec test() :: my_type\"\n        , test \"TypeAlias argument substitution\" <|\n            \\() ->\n                \"type alias MyType a = List a\"\n                    |++ \"test : MyType Int\"\n                    |++ \"test = 0\"\n                    |> has \"@spec test() :: my_type(integer)\"\n        , test \"TypeAlias argument substitution between types\" <|\n            \\() ->\n                \"type alias AnyKey val = (a, val)\"\n                    |++ \"type alias Val a = AnyKey a\"\n                    |++ \"test : Val Int\"\n                    |++ \"test = 0\"\n                    |> has \"@spec test() :: val(integer)\"\n        , test \"TypeAlias no argument substitution in Type\" <|\n            \\() ->\n                \"type alias MyList a = List a\"\n                    |++ \"type Val a = AnyKey (MyList a)\"\n                    |++ \"test : Val Int\"\n                    |++ \"test = 0\"\n                    |> has \"@spec test() :: val\"\n\n        -- Polymorhpism\n        , test \"Polymorhpic record alias\" <|\n            \\() ->\n                \"type Wende = Wende\"\n                    |++ \"type alias Wendable a = { a | wendify : (a -> Wende)}\"\n                    |++ \"type alias Man = Wendable { gender: Bool }\"\n                    |++ \"a : Man -> String \"\n                    |++ \"a = 0\"\n                    |> has \"@type man :: %{wendify: (%{gender: boolean} -> wende), gender: boolean\"\n        , test \"Multi polymorhpic record alias\" <|\n            \\() ->\n                \"type Wende = Wende\"\n                    |++ \"type alias Namable a = { a | name : String }\"\n                    |++ \"type alias Agable a =  { a | age: Int }\"\n                    |++ \"type alias Man = Namable (Agable { gender : String })\"\n                    |++ \"a : Man -> String \"\n                    |++ \"a = 0\"\n                    |> has \"@type man :: %{name: String.t, age: integer, gender: String.t}\"\n        , test \"Interface as type\" <|\n            \\() ->\n                \"type alias Namable a = { a | name : String }\"\n                    |++ \"getName : Namable a -> String\"\n                    |++ \"getName = 0\"\n                    |> has \"@spec get_name(%{name: String.t}) :: String.t\"\n        ]\n\n\nfileImports =\n    describe \"Imports\"\n        [ test \"Same alias names in two files\" <|\n            \\() ->\n                \"\"\"\n>>>> FileA.elm\nmodule A exposing (..)\ntype alias A = Int\n\n>>>> FileB.elm\nmodule B exposing (..)\ntype alias B = Float\n    \"\"\"\n                    -- If it compiles it's already good\n                    |> hasFull \"\"\n        , test \"Imported alias from another file\" <|\n            \\() ->\n                \"\"\"\n>>>> FileA.elm\nmodule A exposing (..)\ntype alias MyAlias = Int\n\n>>>> FileB.elm\nmodule B exposing (..)\nimport A exposing (..)\n\na : MyAlias\na = 1\n    \"\"\"\n                    |> hasFull \"@spec a() :: A.my_alias\"\n        , test \"Imported type from another file\" <|\n            \\() ->\n                \"\"\"\n>>>> FileA.elm\nmodule A exposing (..)\ntype MyType = TypeA Int | TypeB Int\n\na : MyType\na = TypeA\n\n>>>> FileB.elm\nmodule B exposing (..)\nimport A exposing (..)\n\na : MyType\na = TypeB\n    \"\"\"\n                    |> hasFull \"fn x1 -> {:type_b, x1} end\"\n        , test \"Named type from another aliased module\" <|\n            \\() ->\n                \"\"\"\n>>>> Foo.elm\nmodule Foo exposing (Baz)\ntype alias Baz = {a: Int, b: Int}\n\n>>>> Bar.elm\nmodule Bar exposing (..)\n\nimport Foo\n\na : Foo.Baz\na = Foo.Baz 10 20\n            \"\"\"\n                    |> hasFull \"%{a: 10, b: 20}\"\n        , test \"Named type from another aliased module with as\" <|\n            \\() ->\n                \"\"\"\n>>>> Foo.elm\nmodule Foo.Fighters exposing (Baz)\ntype alias Baz = {a: Int, b: Int}\n\n>>>> Bar.elm\nmodule Bar exposing (..)\n\nimport Foo.Fighters as Fighters exposing(a)\n\na : Fighters.Baz\na = Fighters.Baz 10 20\n            \"\"\"\n                    |> hasFull \"%{a: 10, b: 20}\"\n        , test \"Imported specific type from another file\" <|\n            \\() ->\n                \"\"\"\n>>>> FileA.elm\nmodule A exposing (..)\ntype MyType = TypeA Int | TypeB Int\n\na : MyType\na = TypeA\n\n>>>> FileB.elm\nmodule B exposing (..)\nimport A exposing (MyType(TypeB))\n\na : MyType\na = TypeA\n    \"\"\"\n                    |> hasFull \":type_a\"\n        , test \"Imported all union types from another file\" <|\n            \\() ->\n                \"\"\"\n>>>> FileA.elm\nmodule A exposing (..)\ntype MyType = TypeA Int | TypeB Int\n\na : MyType\na = TypeA\n\n>>>> FileB.elm\nmodule B exposing (..)\nimport A exposing (MyType(..))\n\na : MyType\na = (TypeA, TypeB)\n    \"\"\"\n                    |> hasFull \":type_a\"\n        , test \"Doesn't import what imports imported\" <|\n            \\() ->\n                \"\"\"\n>>>> A.elm\nmodule A exposing (..)\ntype Invisible = Invi Int\n\n>>>> B.elm\nmodule B exposing (..)\nimport A exposing (..)\n\n>>>> C.elm\nmodule C exposing (..)\nimport A exposing (..)\n\n>>>> B.elm\nmodule D exposing (..)\nimport B exposing (..)\nimport C exposing (..)\n\na : Invisible\na = 1\n    \"\"\"\n                    |> hasFull \"invisible\"\n        , test \"Qualified imports work too\" <|\n            \\() ->\n                \"\"\"\n>>>> a.elm\nmodule A exposing (A)\ntype As a = Tag a\n\n>>>> b.elm\nmodule B exposing (..)\nimport A exposing (As)\na : As a\na = Tag\n       \"\"\"\n                    |> hasFull \"fn x1 -> {:tag, x1} end\"\n        , test \"Conflicted imports are excepts\" <|\n            \\() ->\n                \"\"\"\n>>>> a.elm\nmodule Something.A exposing (a)\na : a -> Int\na _ = 1\n\n>>>> b.elm\nmodule Something.B exposing (..)\nimport Something.A exposing (..)\na : a -> Int\na _ = 10\n       \"\"\"\n                    |> hasFull \"import Something.A, except: [{:'a', 0}, {:'a', 1}]\"\n        ]\n\n\nletIns : Test\nletIns =\n    describe \"Let in constructs\"\n        [ test \"Allows to reffer variables in reversed order\" <|\n            \\() -> \"\"\"\n            test = let\n              a = b\n              b = 2\n            in a\n            \"\"\" |> has \"b = 2a = b\"\n        , test \"More advanced order\" <|\n            \\() -> \"\"\"\n              test = let\n                a = b\n                b = 2\n                c = a\n                d = a + c\n              in d\n                \"\"\" |> has \"b = 2a = bc = ad = (a + c)\"\n        , test \"Functions work too\" <|\n            \\() -> \"\"\"\n              test = let\n                a = \\\\() -> b\n                b = 10\n              in d\n                \"\"\" |> has \"b = 10a = fn {} -> b end\"\n        , test \"Union types aren't functions\" <|\n            \\() -> \"\"\"\n              test = let\n                A a = A 1\n                b = 10\n              in d\n                \"\"\" |> has \"{:a, a} = {:a, 1}b = 10\"\n        , test \"Sugared functions work too (with arguments)\" <|\n            \\() -> \"\"\"\n              test = let\n                a x = x + b\n                b = 10\n                x = 1\n              in x\n                \"\"\" |> has \"b = 10a = rec a, fn x -> (x + b) endx = 1xend\"\n        , test \"Multiple sugared functions work too\" <|\n            \\() -> \"\"\"\n              test = let\n                a x = x + b\n                b a = a\n                x = 1\n              in x\n                \"\"\" |> has \"b = rec b, fn a -> a enda = rec a, fn x -> (x + b) endx = 1xend\"\n        , test \"Doesn't mind shadowing\" <|\n            \\() -> \"\"\"\n              test = let\n                a = \\\\b -> b\n                b = 10\n              in d\n                \"\"\" |> has \"a = fn b -> b endb = 10\"\n        , test \"Doesn't mind destructuring\" <|\n            \\() -> \"\"\"\n                test = let\n                  newX = x + 1\n                  (x, y) = (1, 2)\n                  newY = y + 1\n                in newX\n                  \"\"\" |> has \"{x, y} = {1, 2}new_x = (x + 1)new_y = (y + 1)\"\n\n        -- , test \"Solves simple mutual recursion\" <|\n        --     \\() -> \"\"\"\n        --       test =\n        --         let\n        --           fx a = fy + 1\n        --           fy b = fx + 1\n        --         in fx 10\n        --           \"\"\" |> has \"{fx, fy} = let [fx: fn a -> \"\n        -- , test \"Solves mutual recursion\" <|\n        --     \\() -> \"\"\"\n        --       test =\n        --         let\n        --           fx x = case x of\n        --               0 -> 0\n        --               x -> fy x - 1\n        --           end\n        --           fy x = case x of\n        --               0 -> 0\n        --               x -> fx x - 1\n        --           end\n        --         in fx 10\n        --           \"\"\" |> has \"{fx, fy} = let [fx: fn x -> \"\n        -- , test \"Solves mutual relation\" <|\n        --     \\() -> \"\"\"\n        --       test =\n        --         let\n        --           x = y + 1\n        --           y = x + 1\n        --         in x\n        --           \"\"\" |> has \"{x, y} = let [x: (y + 1)\"\n        ]\n\n\ncaseOfs =\n    describe \"Case ofs\"\n        [ test \"Simple case of\" <|\n            \\() ->\n                \"\"\"\ntest =\n  case x of\n    1 -> 1\n    2 -> 2\n                \"\"\" |> has \"case x() do1 ->12 ->2end\"\n        , test \"Nested case of\" <|\n            \\() ->\n                \"\"\"\ntest =\n  case x of\n    1 -> 1\n    2 -> case y of\n      0 -> 0\n    3 -> 3\n\n            \"\"\" |> has \"case x() do1 ->12 ->case y() do0 ->0end3 ->3end\"\n        ]\n\n\naccessMacros : Test\naccessMacros =\n    describe \"Access macros compile properly\"\n        [ test \"Update\"\n            (\\() ->\n                \"test = updateIn .a (\\\\a -> a + 1)\" |> has \"update_in_([:a]).(fn a -> (a + 1) end)\"\n            )\n        , test \"Update5\"\n            (\\() ->\n                \"test = updateIn5 .a .b .c .d .e (\\\\a -> a + 1) v\" |> has \"update_in_([:a, :b, :c, :d, :e]).(fn a -> (a + 1) end).(v())\"\n            )\n        , test \"Get\"\n            (\\() ->\n                \"test = getIn3 .something .something .darkSide True v\" |> has \"get_in_([:something, :something, :dark_side]).(:true).(v())\"\n            )\n        , test \"Put\"\n            (\\() ->\n                \"test = putIn4 .a .b .c .d 10 v\" |> has \"put_in_([:a, :b, :c, :d]).(10).(v())\"\n            )\n        ]\n\n\nall : Test\nall =\n    describe \"All\"\n        [ tuples\n        , lists\n        , functions\n        , binOps\n\n        -- Disabled util specs are working correctly\n        , specs\n        , typeAliases\n        , types\n        , records\n        , typeConstructors\n        , doctests\n        , fileImports\n        , letIns\n        , caseOfs\n        , accessMacros\n        ]\n"
  },
  {
    "path": "tests/UnitTests.elm",
    "content": "module UnitTests exposing (..)\n\nimport Test exposing (..)\nimport Expect\n\n\nall : Test\nall =\n    describe \"Test\"\n        [ test \"Test truth\" <|\n            \\() ->\n                Expect.equal \"a\" \"a\"\n        ]\n"
  },
  {
    "path": "tests/elm-package.json",
    "content": "{\n    \"version\": \"1.0.0\",\n    \"summary\": \"Sample Elm Test\",\n    \"repository\": \"https://github.com/user/project.git\",\n    \"license\": \"BSD-3-Clause\",\n    \"source-directories\": [\n        \".\",\n        \"../src\"\n    ],\n    \"exposed-modules\": [],\n    \"dependencies\": {\n        \"elm-lang/core\": \"5.0.0 <= v < 6.0.0\",\n        \"elm-community/elm-test\": \"3.0.0 <= v < 4.0.0\",\n        \"rtfeldman/node-test-runner\": \"3.0.0 <= v < 4.0.0\",\n        \"Bogdanp/elm-ast\": \"8.0.0 <= v < 10.0.0\",\n        \"elm-community/list-extra\": \"6.0.0 <= v < 7.0.0\"\n    },\n    \"elm-version\": \"0.18.0 <= v < 0.19.0\"\n}\n"
  }
]