├── .cargo └── config.toml ├── .github └── workflows │ ├── ci.yml │ ├── coverage.yml │ ├── deploy.yml │ ├── examples-index.yml │ ├── lint.yml │ └── nix.yml ├── .gitignore ├── ARCHITECTURE.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── app ├── Cargo.toml ├── README.md ├── src │ ├── cli │ │ ├── check.rs │ │ ├── clean.rs │ │ ├── compile.rs │ │ ├── doc.rs │ │ ├── format.rs │ │ ├── gen_completions.rs │ │ ├── lex.rs │ │ ├── lift.rs │ │ ├── lsp.rs │ │ ├── mod.rs │ │ ├── run.rs │ │ ├── texify.rs │ │ └── xfunc.rs │ ├── main.rs │ ├── result.rs │ └── utils │ │ ├── ignore_colors.rs │ │ └── mod.rs └── tests │ └── integration_test.rs ├── bench ├── Cargo.toml └── src │ └── main.rs ├── codecov.yml ├── contrib ├── coq │ └── stlc.v └── nix │ ├── README.md │ ├── default.nix │ ├── package.nix │ └── shell.nix ├── examples ├── encoding_church.pol ├── encoding_fu_stump.pol ├── encoding_parigot.pol ├── encoding_scott.pol ├── eq.pol ├── functor.pol ├── index.json ├── pi.pol ├── set.pol ├── stlc.pol ├── strong_existentials.pol └── tutorial.pol ├── flake.lock ├── flake.nix ├── lang ├── ast │ ├── Cargo.toml │ └── src │ │ ├── ctx │ │ ├── def.rs │ │ ├── levels.rs │ │ ├── map_idx.rs │ │ ├── mod.rs │ │ └── values.rs │ │ ├── decls.rs │ │ ├── exp │ │ ├── anno.rs │ │ ├── args.rs │ │ ├── call.rs │ │ ├── case.rs │ │ ├── dot_call.rs │ │ ├── hole.rs │ │ ├── local_comatch.rs │ │ ├── local_match.rs │ │ ├── mod.rs │ │ ├── telescope_inst.rs │ │ ├── typ_ctor.rs │ │ ├── type_univ.rs │ │ └── variable.rs │ │ ├── ident.rs │ │ ├── lib.rs │ │ └── traits │ │ ├── contains_metavars.rs │ │ ├── has_span.rs │ │ ├── has_type.rs │ │ ├── mod.rs │ │ ├── occurs.rs │ │ ├── rename.rs │ │ ├── shift.rs │ │ ├── subst.rs │ │ └── zonk.rs ├── backend │ ├── Cargo.toml │ └── src │ │ ├── ast2ir │ │ ├── decls.rs │ │ ├── exprs.rs │ │ ├── mod.rs │ │ └── traits.rs │ │ ├── ir │ │ ├── decls.rs │ │ ├── exprs.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ └── result.rs ├── docs │ ├── Cargo.toml │ ├── src │ │ ├── doc.rs │ │ ├── generate.rs │ │ ├── generate_docs.rs │ │ ├── lib.rs │ │ ├── printer.rs │ │ ├── render │ │ │ ├── html.rs │ │ │ └── mod.rs │ │ ├── sidebar.rs │ │ └── util.rs │ └── templates │ │ ├── codata.html │ │ ├── codef.html │ │ ├── data.html │ │ ├── def.html │ │ ├── index.html │ │ ├── infix.html │ │ ├── let.html │ │ ├── module.html │ │ └── style.css ├── driver │ ├── Cargo.toml │ └── src │ │ ├── asserts.rs │ │ ├── cache.rs │ │ ├── codespan.rs │ │ ├── database.rs │ │ ├── dependency_graph.rs │ │ ├── edit.rs │ │ ├── fs.rs │ │ ├── info │ │ ├── collect.rs │ │ ├── data.rs │ │ ├── item.rs │ │ ├── lookup.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── lift.rs │ │ ├── paths.rs │ │ ├── result.rs │ │ ├── spans.rs │ │ └── xfunc.rs ├── elaborator │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── conversion_checking │ │ ├── constraints.rs │ │ ├── mod.rs │ │ └── unify.rs │ │ ├── index_unification │ │ ├── constraints.rs │ │ ├── dec.rs │ │ ├── mod.rs │ │ └── unify.rs │ │ ├── lib.rs │ │ ├── normalizer │ │ ├── env.rs │ │ ├── eval.rs │ │ ├── mod.rs │ │ ├── normalize.rs │ │ └── val.rs │ │ ├── result.rs │ │ └── typechecker │ │ ├── ctx.rs │ │ ├── decls │ │ ├── codatatype.rs │ │ ├── codefinition.rs │ │ ├── datatype.rs │ │ ├── definition.rs │ │ ├── global_let.rs │ │ ├── infix_declaration.rs │ │ └── mod.rs │ │ ├── erasure.rs │ │ ├── exprs │ │ ├── anno.rs │ │ ├── call.rs │ │ ├── dot_call.rs │ │ ├── hole.rs │ │ ├── local_comatch.rs │ │ ├── local_match.rs │ │ ├── mod.rs │ │ ├── typ_ctor.rs │ │ ├── type_univ.rs │ │ └── variable.rs │ │ ├── mod.rs │ │ ├── type_info_table │ │ ├── build.rs │ │ ├── lookup.rs │ │ └── mod.rs │ │ └── util.rs ├── lowering │ ├── Cargo.toml │ └── src │ │ ├── ctx.rs │ │ ├── lib.rs │ │ ├── lower │ │ ├── decls │ │ │ ├── codata_declaration.rs │ │ │ ├── codefinition.rs │ │ │ ├── data_declaration.rs │ │ │ ├── definition.rs │ │ │ ├── infix_declaration.rs │ │ │ ├── mod.rs │ │ │ └── toplevel_let.rs │ │ ├── exp │ │ │ ├── anno.rs │ │ │ ├── args.rs │ │ │ ├── binop.rs │ │ │ ├── call.rs │ │ │ ├── dot_call.rs │ │ │ ├── hole.rs │ │ │ ├── lam.rs │ │ │ ├── local_comatch.rs │ │ │ ├── local_let.rs │ │ │ ├── local_match.rs │ │ │ ├── mod.rs │ │ │ ├── nat_lit.rs │ │ │ └── parens.rs │ │ └── mod.rs │ │ ├── result.rs │ │ └── symbol_table │ │ ├── build.rs │ │ ├── lookup.rs │ │ └── mod.rs ├── lsp │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── capabilities.rs │ │ ├── codeactions.rs │ │ ├── conversion │ │ ├── mod.rs │ │ └── uri_to_url.rs │ │ ├── diagnostics.rs │ │ ├── format.rs │ │ ├── gotodefinition.rs │ │ ├── hover.rs │ │ ├── lib.rs │ │ └── server.rs ├── miette_util │ ├── Cargo.toml │ └── src │ │ ├── codespan.rs │ │ └── lib.rs ├── parser │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── cst │ │ ├── decls.rs │ │ ├── exp.rs │ │ ├── ident.rs │ │ └── mod.rs │ │ ├── grammar │ │ ├── cst.lalrpop │ │ ├── mod.rs │ │ └── util.rs │ │ ├── lexer │ │ └── mod.rs │ │ ├── lib.rs │ │ └── result.rs ├── printer │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── render │ │ ├── latex.rs │ │ ├── mod.rs │ │ └── termcolor.rs │ │ ├── theme.rs │ │ ├── tokens.rs │ │ ├── types.rs │ │ └── util.rs └── transformations │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── lifting │ ├── fv.rs │ ├── mod.rs │ └── signature.rs │ └── xfunc │ ├── matrix.rs │ ├── mod.rs │ └── result.rs ├── rustfmt.toml ├── scripts ├── check_examples_index.sh └── git-hooks │ └── pre-commit ├── std ├── README.md ├── codata │ ├── fun.pol │ ├── pair.pol │ ├── pi.pol │ ├── sigma.pol │ ├── stream.pol │ └── unit.pol └── data │ ├── bool.pol │ ├── eq.pol │ ├── list.pol │ ├── nat.pol │ ├── option.pol │ ├── ordering.pol │ ├── pair.pol │ ├── result.pol │ ├── sigma.pol │ ├── unit.pol │ ├── vec.pol │ └── void.pol ├── test ├── suites │ ├── fail-check │ │ ├── 001.expected │ │ ├── 001.pol │ │ ├── 002.expected │ │ ├── 002.pol │ │ ├── 003.expected │ │ ├── 003.pol │ │ ├── 004.expected │ │ ├── 004.pol │ │ ├── 005.expected │ │ ├── 005.pol │ │ ├── 006.expected │ │ ├── 006.pol │ │ ├── 007.expected │ │ ├── 007.pol │ │ ├── 008.expected │ │ ├── 008.pol │ │ ├── 009.expected │ │ ├── 009.pol │ │ ├── 010.expected │ │ ├── 010.pol │ │ ├── 011-escaping-hole.expected │ │ ├── 011-escaping-hole.pol │ │ ├── 012-nonlinear-args.expected │ │ ├── 012-nonlinear-args.pol │ │ ├── 013-eta-comatch.expected │ │ ├── 013-eta-comatch.pol │ │ ├── Regr-321.expected │ │ ├── Regr-321.pol │ │ ├── Regr-348.expected │ │ ├── Regr-348.pol │ │ ├── Regr-403.expected │ │ ├── Regr-403.pol │ │ └── suite.toml │ ├── fail-lower │ │ ├── L-001.expected │ │ ├── L-001.pol │ │ ├── L-002-01.expected │ │ ├── L-002-01.pol │ │ ├── L-002-02.expected │ │ ├── L-002-02.pol │ │ ├── L-002-03.expected │ │ ├── L-002-03.pol │ │ ├── L-002-04.expected │ │ ├── L-002-04.pol │ │ ├── L-002-05.expected │ │ ├── L-002-05.pol │ │ ├── L-003.expected │ │ ├── L-003.pol │ │ ├── L-005.expected │ │ ├── L-005.pol │ │ ├── L-010.expected │ │ ├── L-010.pol │ │ ├── L-011-ctor.expected │ │ ├── L-011-ctor.pol │ │ ├── L-011-def.expected │ │ ├── L-011-def.pol │ │ ├── L-011-tyctor.expected │ │ ├── L-011-tyctor.pol │ │ ├── L-012.expected │ │ ├── L-012.pol │ │ ├── L-015.expected │ │ ├── L-015.pol │ │ ├── L-016a.expected │ │ ├── L-016a.pol │ │ ├── L-016b.expected │ │ ├── L-016b.pol │ │ ├── L-016c.expected │ │ ├── L-016c.pol │ │ ├── L-016d.expected │ │ ├── L-016d.pol │ │ ├── L-016e.expected │ │ ├── L-016e.pol │ │ ├── L-016f.expected │ │ ├── L-016f.pol │ │ ├── L-017.expected │ │ ├── L-017.pol │ │ ├── L-018.expected │ │ ├── L-018.pol │ │ ├── L-019a.expected │ │ ├── L-019a.pol │ │ ├── L-019b.expected │ │ ├── L-019b.pol │ │ ├── L-019c.expected │ │ ├── L-019c.pol │ │ ├── L-019d.expected │ │ ├── L-019d.pol │ │ ├── L-let-lower.expected │ │ ├── L-let-lower.pol │ │ ├── Regr-318a.expected │ │ ├── Regr-318a.pol │ │ ├── Regr-318b.expected │ │ ├── Regr-318b.pol │ │ ├── Regr-408.expected │ │ ├── Regr-408.pol │ │ ├── Regr-86.expected │ │ ├── Regr-86.pol │ │ └── suite.toml │ ├── fail-parse │ │ ├── P-001.expected │ │ ├── P-001.pol │ │ ├── P-002.expected │ │ ├── P-002.pol │ │ ├── P-003.expected │ │ ├── P-003.pol │ │ ├── P-004-let-1.expected │ │ ├── P-004-let-1.pol │ │ ├── P-005-let-2.expected │ │ ├── P-005-let-2.pol │ │ └── suite.toml │ └── success │ │ ├── 001.ir.expected │ │ ├── 001.pol │ │ ├── 002.ir.expected │ │ ├── 002.pol │ │ ├── 003.ir.expected │ │ ├── 003.pol │ │ ├── 004.ir.expected │ │ ├── 004.pol │ │ ├── 005.ir.expected │ │ ├── 005.pol │ │ ├── 006.ir.expected │ │ ├── 006.pol │ │ ├── 007.ir.expected │ │ ├── 007.pol │ │ ├── 008.ir.expected │ │ ├── 008.pol │ │ ├── 009.ir.expected │ │ ├── 009.pol │ │ ├── 010.ir.expected │ │ ├── 010.pol │ │ ├── 011.ir.expected │ │ ├── 011.pol │ │ ├── 012.ir.expected │ │ ├── 012.pol │ │ ├── 013.ir.expected │ │ ├── 013.pol │ │ ├── 014.ir.expected │ │ ├── 014.pol │ │ ├── 015.ir.expected │ │ ├── 015.pol │ │ ├── 016-named-args.ir.expected │ │ ├── 016-named-args.pol │ │ ├── 017.ir.expected │ │ ├── 017.pol │ │ ├── 018.ir.expected │ │ ├── 018.pol │ │ ├── 019-absurd.ir.expected │ │ ├── 019-absurd.pol │ │ ├── 020-motive.ir.expected │ │ ├── 020-motive.pol │ │ ├── 021-evalorder.ir.expected │ │ ├── 021-evalorder.pol │ │ ├── 022-implicit-list.ir.expected │ │ ├── 022-implicit-list.pol │ │ ├── 023-comatches.ir.expected │ │ ├── 023-comatches.pol │ │ ├── 024-gadt.ir.expected │ │ ├── 024-gadt.pol │ │ ├── 025-imports.ir.expected │ │ ├── 025-imports.pol │ │ ├── 026-refinement.ir.expected │ │ ├── 026-refinement.pol │ │ ├── 026-typedhole.ir.expected │ │ ├── 026-typedhole.pol │ │ ├── 027-colist.ir.expected │ │ ├── 027-colist.pol │ │ ├── 028-boolrep.ir.expected │ │ ├── 028-boolrep.pol │ │ ├── 029-arith.ir.expected │ │ ├── 029-arith.pol │ │ ├── 030-buffer.ir.expected │ │ ├── 030-buffer.pol │ │ ├── 031-classical-logic.ir.expected │ │ ├── 031-classical-logic.pol │ │ ├── 032-expressions-case-study.ir.expected │ │ ├── 032-expressions-case-study.pol │ │ ├── 033-setoid.ir.expected │ │ ├── 033-setoid.pol │ │ ├── 034-local-matches.ir.expected │ │ ├── 034-local-matches.pol │ │ ├── 035-stlc-bool.ir.expected │ │ ├── 035-stlc-bool.pol │ │ ├── 036-webserver.ir.expected │ │ ├── 036-webserver.pol │ │ ├── 037-vect.ir.expected │ │ ├── 037-vect.pol │ │ ├── 038-erase-hole.ir.expected │ │ ├── 038-erase-hole.pol │ │ ├── 039-metavars-accross-decls.ir.expected │ │ ├── 039-metavars-accross-decls.pol │ │ ├── 040-absurd-lam.ir.expected │ │ ├── 040-absurd-lam.pol │ │ ├── 041-eta-comatch.ir.expected │ │ ├── 041-eta-comatch.pol │ │ ├── Regr-137.ir.expected │ │ ├── Regr-137.pol │ │ ├── Regr-230.ir.expected │ │ ├── Regr-230.pol │ │ ├── Regr-230b.ir.expected │ │ ├── Regr-230b.pol │ │ ├── Regr-250.ir.expected │ │ ├── Regr-250.pol │ │ ├── Regr-271.ir.expected │ │ ├── Regr-271.pol │ │ ├── Regr-297.ir.expected │ │ ├── Regr-297.pol │ │ ├── Regr-341a.ir.expected │ │ ├── Regr-341a.pol │ │ ├── Regr-341b.ir.expected │ │ ├── Regr-341b.pol │ │ ├── Regr-341c.ir.expected │ │ ├── Regr-341c.pol │ │ ├── Regr-348.ir.expected │ │ ├── Regr-348.pol │ │ ├── Regr-403.ir.expected │ │ ├── Regr-403.pol │ │ ├── Regr-442.ir.expected │ │ ├── Regr-442.pol │ │ └── suite.toml └── test-runner │ ├── Cargo.toml │ └── src │ ├── index.rs │ ├── main.rs │ ├── phases.rs │ ├── runner.rs │ └── suites.rs └── web ├── .eslintignore ├── .eslintrc.yaml ├── .gitignore ├── .prettierrc.yaml ├── .stylelintignore ├── .stylelintrc.json ├── Makefile ├── README.md ├── crates └── browser │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── source.rs ├── package-lock.json ├── package.json ├── packages └── app │ ├── .gitignore │ ├── .prettierignore │ ├── assets │ ├── editor.css │ └── editor.html │ ├── declarations.d.ts │ ├── package.json │ ├── src │ ├── @types │ │ └── global.d.ts │ └── editor │ │ ├── app.ts │ │ ├── client.ts │ │ ├── codec.ts │ │ ├── codec │ │ ├── bytes.ts │ │ ├── demuxer.ts │ │ ├── headers.ts │ │ ├── map.ts │ │ └── queue.ts │ │ ├── index.ts │ │ ├── language-configuration.json │ │ ├── language.ts │ │ ├── pol.tmLanguage.json │ │ ├── server.ts │ │ ├── tracer.ts │ │ └── workers.ts │ ├── tsconfig.json │ └── webpack.config.js └── tsconfig.json /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = "--cfg=web_sys_unstable_apis" 3 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Codecov Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: 9 | - opened 10 | - synchronize 11 | 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | coverage: 17 | runs-on: ubuntu-latest 18 | env: 19 | CARGO_TERM_COLOR: always 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Install Rust 23 | run: rustup update stable 24 | - name: Install cargo-llvm-cov 25 | uses: taiki-e/install-action@cargo-llvm-cov 26 | - name: Generate code coverage 27 | run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info 28 | - name: Upload coverage to Codecov 29 | uses: codecov/codecov-action@v5 30 | with: 31 | files: lcov.info 32 | token: ${{ secrets.CODECOV_TOKEN }} 33 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Web Demo 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - run: | 16 | cd web/ 17 | make deps 18 | make build 19 | - run: | 20 | cd web/packages/app/dist && zip -r ../../../../web-demo-latest.zip ./* 21 | - uses: softprops/action-gh-release@v1 22 | with: 23 | tag_name: latest 24 | draft: false 25 | prerelease: false 26 | files: web-demo-latest.zip 27 | env: 28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 29 | - run: | 30 | curl -X POST \ 31 | -H "Accept: application/vnd.github.v3+json" \ 32 | -H "Authorization: token ${{ secrets.WEB_TRIGGER_DEPLOY_TOKEN }}" \ 33 | https://api.github.com/repos/polarity-lang/polarity-lang.github.io/dispatches \ 34 | -d '{"event_type":"trigger-deploy"}' 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/examples-index.yml: -------------------------------------------------------------------------------- 1 | name: Check Examples Index 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'examples/**' 7 | - 'examples/index.json' 8 | pull_request: 9 | paths: 10 | - 'examples/**' 11 | - 'examples/index.json' 12 | 13 | permissions: 14 | contents: read 15 | statuses: write 16 | 17 | jobs: 18 | check-index: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v3 22 | 23 | - name: Install jq 24 | run: sudo apt-get install -y jq 25 | 26 | - name: Check index 27 | run: | 28 | ./scripts/check_examples_index.sh 29 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lint Code Base 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | types: 10 | - opened 11 | - synchronize 12 | 13 | permissions: read-all 14 | 15 | jobs: 16 | build: 17 | name: Lint Code Base 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout Code 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | 26 | - name: Lint Code Base 27 | uses: super-linter/super-linter/slim@v6.3.0 28 | env: 29 | # JSCPD is disabled because it falsely flags duplicated Rust generic parameter definitions 30 | VALIDATE_JSCPD: false 31 | # We use eslint instead of the linter named "standard" 32 | VALIDATE_JAVASCRIPT_STANDARD: false 33 | # We use prettier rather than ts-standard 34 | TYPESCRIPT_DEFAULT_STYLE: prettier 35 | VALIDATE_HTML: false 36 | # We use a slightly different stylelint version/setup 37 | VALIDATE_CSS: false 38 | # We don't validate formatting of bash scripts 39 | VALIDATE_SHELL_SHFMT: false 40 | VALIDATE_NATURAL_LANGUAGE: false 41 | VALIDATE_MARKDOWN: false 42 | DEFAULT_BRANCH: main 43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | target 3 | # direnv 4 | .envrc 5 | .direnv 6 | 7 | *.zip 8 | target_pol 9 | 10 | # nix 11 | result 12 | result- 13 | 14 | # Editors 15 | .vscode/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | We use the `YYYY-MM-DD` date format. 8 | 9 | ## [Unreleased] 10 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "lang/ast", 4 | "lang/parser", 5 | "lang/lowering", 6 | "lang/lsp", 7 | "lang/miette_util", 8 | "lang/printer", 9 | "lang/elaborator", 10 | "lang/driver", 11 | "lang/transformations", 12 | "lang/backend", 13 | "web/crates/browser", 14 | "app", 15 | "bench", 16 | "test/test-runner", 17 | ] 18 | resolver = "2" 19 | default-members = ["app"] 20 | 21 | [workspace.package] 22 | version = "0.1.0" 23 | edition = "2024" 24 | rust-version = "1.85" 25 | authors = ["Tim Süberkrüb", "David Binder"] 26 | license = "MIT OR Apache-2.0" 27 | homepage = "https://polarity-lang.github.io/" 28 | repository = "https://github.com/polarity/polarity" 29 | categories = ["compilers"] 30 | 31 | [workspace.dependencies] 32 | # fancy error messages 33 | miette = { version = "7" } 34 | thiserror = { version = "1" } 35 | # lsp server 36 | lsp-types = { version = "0.97" } 37 | tower-lsp-server = { version = "0.21" , default-features = false, features = [ 38 | "runtime-agnostic", 39 | ] } 40 | # ignoring fields when deriving traits (e.g. Eq, Hash) 41 | derivative = { version = "2" } 42 | # big integers 43 | num-bigint = { version = "0.4" } 44 | # url (for file locations) 45 | url = { version = "2.5.0" } 46 | pretty = { version = "0.11", features = ["termcolor"] } 47 | # logging infrastructure 48 | log = "0.4.21" 49 | env_logger = "0.11.3" 50 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: install 2 | install: 3 | @cargo build --release 4 | @cargo install --offline --locked --path app --force 5 | 6 | .PHONY: check 7 | check: lint test 8 | 9 | .PHONY: lint 10 | lint: 11 | @cargo clippy --all -- -Dwarnings 12 | @cargo fmt --all --check 13 | @(cd web; make lint) 14 | 15 | .PHONY: test 16 | test: 17 | @cargo test --workspace 18 | 19 | .PHONY: bench 20 | bench: 21 | @cargo run -p polarity-bench -- --bench 22 | 23 | .PHONY: update-expected 24 | update-expected: 25 | @cargo test -p test-runner -- --update-expected 26 | 27 | 28 | .PHONY: coverage 29 | coverage: 30 | @echo "Make sure to install via cargo install cargo-llvm-cov first" 31 | @cargo llvm-cov --workspace --html 32 | @cargo llvm-cov --workspace --open 33 | 34 | -------------------------------------------------------------------------------- /app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "polarity" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [[bin]] 15 | name = "pol" 16 | path = "src/main.rs" 17 | 18 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 19 | # cli 20 | clap = { version = "4", features = ["derive"] } 21 | clap_complete = { version = "4.5.38" } 22 | termsize = "0.1" 23 | # fancy error messages 24 | miette = { workspace = true, features = ["fancy"] } 25 | thiserror = { workspace = true } 26 | # Logging infrastructure 27 | env_logger = { workspace = true } 28 | log = { workspace = true } 29 | # lsp 30 | tokio = { version = "1", features = ["rt-multi-thread"] } 31 | futures = "0.3" 32 | async-std = "1" 33 | tower-lsp-server = { workspace = true } 34 | # workspace members 35 | driver = { path = "../lang/driver" } 36 | elaborator = { path = "../lang/elaborator" } 37 | ast = { path = "../lang/ast" } 38 | printer = { path = "../lang/printer" } 39 | parser = { path = "../lang/parser" } 40 | lsp-server = { path = "../lang/lsp" } 41 | docs = { path = "../lang/docs" } 42 | 43 | [dev-dependencies] 44 | # For testing the binary 45 | assert_cmd = "2.0.14" 46 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # CLI application 2 | 3 | ## Requirements 4 | 5 | * [Rust and Cargo](https://www.rust-lang.org/tools/install) 6 | 7 | ## Build 8 | 9 | ```sh 10 | cargo build 11 | ``` 12 | 13 | ## Run 14 | 15 | Start interactive REPL: 16 | 17 | ```sh 18 | cargo run 19 | ``` 20 | 21 | Run a file: 22 | 23 | ```sh 24 | cargo run -- run 25 | ``` 26 | 27 | Print available command-line options: 28 | 29 | ```sh 30 | cargo run -- --help 31 | ``` 32 | -------------------------------------------------------------------------------- /app/src/cli/check.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use driver::Database; 4 | 5 | #[derive(clap::Args)] 6 | pub struct Args { 7 | #[clap(value_parser, value_name = "FILE")] 8 | filepath: PathBuf, 9 | } 10 | 11 | pub async fn exec(cmd: Args) -> miette::Result<()> { 12 | let mut db = Database::from_path(&cmd.filepath); 13 | let uri = db.resolve_path(&cmd.filepath)?; 14 | let _ = db.ast(&uri).await.map_err(|err| db.pretty_error(&uri, err))?; 15 | println!("{} typechecked successfully!", cmd.filepath.display()); 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /app/src/cli/clean.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use driver::paths::TARGET_PATH; 4 | 5 | pub async fn exec() -> miette::Result<()> { 6 | if std::path::Path::new(TARGET_PATH).exists() { 7 | fs::remove_dir_all(TARGET_PATH).map_err(miette::Report::msg)?; 8 | } 9 | Ok(()) 10 | } 11 | -------------------------------------------------------------------------------- /app/src/cli/compile.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::{Path, PathBuf}; 3 | 4 | use driver::{Database, IR_PATH}; 5 | use printer::{Print, PrintCfg}; 6 | 7 | #[derive(clap::Args)] 8 | pub struct Args { 9 | #[clap(value_parser, value_name = "FILE")] 10 | filepath: PathBuf, 11 | } 12 | 13 | pub async fn exec(cmd: Args) -> miette::Result<()> { 14 | let mut db = Database::from_path(&cmd.filepath); 15 | let uri = db.resolve_path(&cmd.filepath)?; 16 | let ir = db.ir(&uri).await.map_err(|err| db.pretty_error(&uri, err))?; 17 | 18 | if !Path::new(IR_PATH).exists() { 19 | fs::create_dir_all(IR_PATH).expect("Failed to create IR directory"); 20 | } 21 | 22 | let ir_path = target_path(&cmd.filepath); 23 | let mut file = fs::File::create(&ir_path).expect("Failed to create file"); 24 | let cfg = PrintCfg::default(); 25 | ir.print_io(&cfg, &mut file).expect("Failed to print to file"); 26 | 27 | Ok(()) 28 | } 29 | 30 | fn target_path(filepath: &Path) -> PathBuf { 31 | let mut path = 32 | Path::new(IR_PATH).join(filepath.file_name().unwrap().to_string_lossy().as_ref()); 33 | path.set_extension("ir"); 34 | path 35 | } 36 | -------------------------------------------------------------------------------- /app/src/cli/doc.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::path::PathBuf; 3 | 4 | use docs::get_target_path; 5 | use docs::open; 6 | use docs::write_html; 7 | 8 | #[derive(clap::Args)] 9 | pub struct Args { 10 | #[clap(value_parser, value_name = "FILE")] 11 | filepath: PathBuf, 12 | #[clap(long, num_args = 0)] 13 | open: bool, 14 | } 15 | 16 | pub async fn exec(cmd: Args) -> miette::Result<()> { 17 | let filepath = &cmd.filepath; 18 | let htmlpath = 19 | get_target_path(&fs::canonicalize(filepath).expect("failed to canonicalize path")); 20 | write_html().await; 21 | if cmd.open { 22 | open(&htmlpath); 23 | } 24 | Ok(()) 25 | } 26 | -------------------------------------------------------------------------------- /app/src/cli/gen_completions.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::File, io::BufWriter, path::PathBuf}; 2 | 3 | use clap::CommandFactory; 4 | use clap_complete::{ 5 | generate, 6 | shells::{Bash, Elvish, Fish, PowerShell, Zsh}, 7 | }; 8 | 9 | use super::Cli; 10 | 11 | #[allow(clippy::enum_variant_names)] 12 | #[derive(clap::ValueEnum, Clone)] 13 | pub enum Shell { 14 | Bash, 15 | Elvish, 16 | Fish, 17 | PowerShell, 18 | Zsh, 19 | } 20 | 21 | #[derive(clap::Args)] 22 | pub struct Args { 23 | /// Target shell 24 | shell: Shell, 25 | /// Where the completion script should be saved. 26 | #[clap(value_parser, value_name = "PATH")] 27 | filepath: PathBuf, 28 | } 29 | 30 | pub async fn exec(cmd: Args) -> miette::Result<()> { 31 | let mut file = BufWriter::new(File::create(cmd.filepath).expect("Failed to create file")); 32 | match cmd.shell { 33 | Shell::Bash => generate(Bash, &mut Cli::command(), "pol", &mut file), 34 | Shell::Elvish => generate(Elvish, &mut Cli::command(), "pol", &mut file), 35 | Shell::Fish => generate(Fish, &mut Cli::command(), "pol", &mut file), 36 | Shell::PowerShell => generate(PowerShell, &mut Cli::command(), "pol", &mut file), 37 | Shell::Zsh => generate(Zsh, &mut Cli::command(), "pol", &mut file), 38 | } 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /app/src/cli/lex.rs: -------------------------------------------------------------------------------- 1 | use std::{fs, path::PathBuf}; 2 | 3 | use parser::lexer::Lexer; 4 | 5 | pub async fn exec(args: Args) -> miette::Result<()> { 6 | let src = fs::read_to_string(&args.filepath).expect("Failed to read file"); 7 | let lexer = Lexer::new(&src); 8 | for tok in lexer { 9 | match tok { 10 | Ok((p1, tok, p2)) => println!("{tok} at ({p1},{p2})"), 11 | Err(err) => println!("{err}"), 12 | } 13 | } 14 | Ok(()) 15 | } 16 | 17 | #[derive(clap::Args)] 18 | pub struct Args { 19 | #[clap(value_parser, value_name = "FILE")] 20 | filepath: PathBuf, 21 | } 22 | -------------------------------------------------------------------------------- /app/src/cli/lift.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io; 3 | use std::path::PathBuf; 4 | 5 | use driver::Database; 6 | 7 | #[derive(clap::Args)] 8 | pub struct Args { 9 | #[clap(value_parser, value_name = "TYPE")] 10 | r#type: String, 11 | #[clap(value_parser, value_name = "FILE")] 12 | filepath: PathBuf, 13 | #[clap(short, long, value_name = "FILE")] 14 | output: Option, 15 | } 16 | 17 | pub async fn exec(cmd: Args) -> miette::Result<()> { 18 | let mut db = Database::from_path(&cmd.filepath); 19 | let uri = db.resolve_path(&cmd.filepath)?; 20 | let edits = db.lift(&uri, &cmd.r#type).await.map_err(miette::Report::msg)?; 21 | 22 | // Write to file or to stdout 23 | let stream: Box = match cmd.output { 24 | Some(path) => Box::new(fs::File::create(path).expect("Failed to create file")), 25 | None => Box::new(io::stdout()), 26 | }; 27 | 28 | let output = db.edited(&uri, edits); 29 | 30 | output.write_to(stream).expect("Failed to write file"); 31 | 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /app/src/cli/lsp.rs: -------------------------------------------------------------------------------- 1 | use tower_lsp_server::{LspService, Server}; 2 | 3 | #[derive(clap::Args)] 4 | pub struct Args {} 5 | 6 | pub async fn exec(_: Args) -> miette::Result<()> { 7 | let stdin = async_std::io::stdin(); 8 | let stdout = async_std::io::stdout(); 9 | let (service, messages) = LspService::new(lsp_server::Server::new); 10 | Server::new(stdin, stdout, messages).serve(service).await; 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /app/src/cli/run.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use miette::Diagnostic; 4 | use thiserror::Error; 5 | 6 | use driver::Database; 7 | use printer::{ColorChoice, Print, StandardStream}; 8 | 9 | #[derive(clap::Args)] 10 | pub struct Args { 11 | #[clap(value_parser, value_name = "FILE")] 12 | filepath: PathBuf, 13 | } 14 | 15 | pub async fn exec(cmd: Args) -> miette::Result<()> { 16 | let mut db = Database::from_path(&cmd.filepath); 17 | let uri = db.resolve_path(&cmd.filepath)?; 18 | let nf = db.run(&uri).await.map_err(|err| db.pretty_error(&uri, err))?; 19 | 20 | match nf { 21 | Some(nf) => print_nf(&nf), 22 | None => return Err(miette::Report::from(MainNotFound {})), 23 | } 24 | Ok(()) 25 | } 26 | 27 | fn print_nf(nf: &ast::Exp) { 28 | let mut stream = StandardStream::stdout(ColorChoice::Auto); 29 | nf.print_colored(&Default::default(), &mut stream).expect("Failed to print to stdout"); 30 | println!(); 31 | } 32 | 33 | #[derive(Error, Diagnostic, Debug)] 34 | #[error("Main expression was not found")] 35 | #[diagnostic(help("Main expressions must be called \"main\" and not take any arguments."))] 36 | pub struct MainNotFound {} 37 | -------------------------------------------------------------------------------- /app/src/cli/xfunc.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::io; 3 | use std::path::PathBuf; 4 | 5 | use driver::{Database, Xfunc}; 6 | 7 | #[derive(clap::Args)] 8 | pub struct Args { 9 | #[clap(value_parser, value_name = "TYPE")] 10 | r#type: String, 11 | #[clap(value_parser, value_name = "FILE")] 12 | filepath: PathBuf, 13 | #[clap(short, long, value_name = "FILE")] 14 | output: Option, 15 | } 16 | 17 | pub async fn exec(cmd: Args) -> miette::Result<()> { 18 | let mut db = Database::from_path(&cmd.filepath); 19 | let uri = db.resolve_path(&cmd.filepath)?; 20 | let Xfunc { edits, .. } = db.xfunc(&uri, &cmd.r#type).await.map_err(miette::Report::msg)?; 21 | 22 | let output = db.edited(&uri, edits); 23 | 24 | // Write to file or to stdout 25 | let stream: Box = match cmd.output { 26 | Some(path) => Box::new(fs::File::create(path).expect("Failed to create file")), 27 | None => Box::new(io::stdout()), 28 | }; 29 | 30 | output.write_to(stream).expect("Failed to write file"); 31 | 32 | Ok(()) 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | mod cli; 3 | #[cfg(not(target_arch = "wasm32"))] 4 | mod result; 5 | 6 | mod utils; 7 | 8 | #[cfg(not(target_arch = "wasm32"))] 9 | fn main() -> miette::Result<()> { 10 | miette::set_panic_hook(); 11 | cli::exec() 12 | } 13 | 14 | #[cfg(target_arch = "wasm32")] 15 | fn main() {} 16 | -------------------------------------------------------------------------------- /app/src/result.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use miette::Diagnostic; 4 | use thiserror::Error; 5 | 6 | #[derive(Error, Diagnostic, Debug)] 7 | #[error("IO Error")] 8 | pub struct IOError { 9 | #[from] 10 | inner: io::Error, 11 | } 12 | -------------------------------------------------------------------------------- /app/src/utils/ignore_colors.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use printer::termcolor::WriteColor; 4 | 5 | pub struct IgnoreColors { 6 | inner: W, 7 | } 8 | 9 | impl IgnoreColors { 10 | pub fn new(inner: W) -> Self { 11 | Self { inner } 12 | } 13 | } 14 | 15 | impl io::Write for IgnoreColors { 16 | fn write(&mut self, buf: &[u8]) -> io::Result { 17 | self.inner.write(buf) 18 | } 19 | 20 | fn flush(&mut self) -> io::Result<()> { 21 | self.inner.flush() 22 | } 23 | } 24 | 25 | impl WriteColor for IgnoreColors { 26 | fn supports_color(&self) -> bool { 27 | false 28 | } 29 | 30 | fn set_color(&mut self, _spec: &printer::ColorSpec) -> io::Result<()> { 31 | Ok(()) 32 | } 33 | 34 | fn reset(&mut self) -> io::Result<()> { 35 | Ok(()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ignore_colors; 2 | -------------------------------------------------------------------------------- /app/tests/integration_test.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | 3 | /// The name of the CLI binary 4 | const BINARY: &str = "pol"; 5 | 6 | /// Check that "pol --version" works correctly 7 | #[test] 8 | fn version_command() { 9 | println!("{:?}", BINARY); 10 | let mut cmd = Command::cargo_bin(BINARY).unwrap(); 11 | let assert = cmd.arg("--version").assert(); 12 | assert.success().stdout("polarity 0.1.0\n"); 13 | } 14 | 15 | /// Check that "pol check" works correctly 16 | #[test] 17 | fn check_command() { 18 | let mut cmd = Command::cargo_bin(BINARY).unwrap(); 19 | let assert = cmd.args(vec!["check", "../examples/encoding_scott.pol"]).assert(); 20 | assert.success().stdout("../examples/encoding_scott.pol typechecked successfully!\n"); 21 | } 22 | 23 | /// Check that "pol check" works correctly 24 | #[test] 25 | fn check_command_2() { 26 | let mut cmd = Command::cargo_bin(BINARY).unwrap(); 27 | let assert = cmd.args(vec!["check", "../examples/encoding_church.pol"]).assert(); 28 | assert.success().stdout("../examples/encoding_church.pol typechecked successfully!\n"); 29 | } 30 | 31 | /// Check that "pol run" works correctly 32 | #[test] 33 | fn run_command() { 34 | let mut cmd = Command::cargo_bin(BINARY).unwrap(); 35 | let assert = 36 | cmd.env("NO_COLOR", "1").args(vec!["run", "../test/suites/success/037-vect.pol"]).assert(); 37 | assert 38 | .success() 39 | .stdout("Cons(S(S(S(Z))), Z, Cons(S(S(Z)), Z, Cons(S(Z), Z, Cons(Z, Z, Nil))))\n"); 40 | } 41 | -------------------------------------------------------------------------------- /bench/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "polarity-bench" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [[bin]] 15 | name = "pol-bench" 16 | path = "src/main.rs" 17 | 18 | [dependencies] 19 | # runtime 20 | tokio = { version = "1", features = ["rt-multi-thread"] } 21 | futures = "0.3" 22 | async-std = "1" 23 | url = "2" 24 | # fancy error messages 25 | miette = { workspace = true, features = ["fancy"] } 26 | # workspace members 27 | driver = { path = "../lang/driver" } 28 | elaborator = { path = "../lang/elaborator" } 29 | ast = { path = "../lang/ast" } 30 | printer = { path = "../lang/printer" } 31 | lsp-server = { path = "../lang/lsp" } 32 | docs = { path = "../lang/docs" } 33 | # benchmarking 34 | criterion = { version = "0.5", features = ["html_reports"] } 35 | -------------------------------------------------------------------------------- /bench/src/main.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, criterion_group, criterion_main}; 2 | use driver::{Database, FileSource, InMemorySource}; 3 | use url::Url; 4 | 5 | const EXAMPLE_STLC: &str = include_str!("../../examples/stlc.pol"); 6 | const EXAMPLE_STRONG_EX: &str = include_str!("../../examples/strong_existentials.pol"); 7 | 8 | fn benchmark_stlc(c: &mut Criterion) { 9 | c.bench_function("stlc.pol", |b| b.iter(|| run(EXAMPLE_STLC))); 10 | } 11 | 12 | fn benchmark_strong_existentials(c: &mut Criterion) { 13 | c.bench_function("strong_existentials.pol", |b| b.iter(|| run(EXAMPLE_STRONG_EX))); 14 | } 15 | 16 | fn run(example: &str) -> miette::Result<()> { 17 | tokio::runtime::Builder::new_multi_thread() 18 | .enable_all() 19 | .build() 20 | .unwrap() 21 | .block_on(run_async(example)) 22 | } 23 | 24 | async fn run_async(example: &str) -> miette::Result<()> { 25 | let mut inmemory_source = InMemorySource::new(); 26 | let uri: Url = "inmemory:///bench.pol".parse().expect("Failed to parse URI"); 27 | inmemory_source.write_string(&uri, example).await.expect("Failed to write inmemory source"); 28 | let mut db = Database::from_source(inmemory_source); 29 | let _ = db.ast(&uri).await.map_err(|err| db.pretty_error(&uri, err)); 30 | Ok(()) 31 | } 32 | 33 | criterion_group!(benches, benchmark_stlc, benchmark_strong_existentials); 34 | criterion_main!(benches); 35 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: # default is the status check's name, not default settings 5 | informational: true 6 | patch: 7 | default: 8 | informational: true 9 | -------------------------------------------------------------------------------- /contrib/nix/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs ? import { }, 3 | ... 4 | }: 5 | { 6 | polarity = pkgs.callPackage ./package.nix { }; 7 | polarity-static = pkgs.pkgsStatic.callPackage ./package.nix { }; 8 | } 9 | -------------------------------------------------------------------------------- /contrib/nix/package.nix: -------------------------------------------------------------------------------- 1 | { rustPlatform, lib, ... }: 2 | rustPlatform.buildRustPackage rec { 3 | pname = "polarity"; 4 | version = "latest"; 5 | src = ../..; 6 | 7 | cargoLock = { 8 | lockFile = "${src}/Cargo.lock"; 9 | }; 10 | 11 | meta = { 12 | description = "A language with Dependendent Data and Codata Types"; 13 | homepage = "https://polarity-lang.github.io/"; 14 | licenses = with lib.licenses; [ 15 | mit 16 | asl20 17 | ]; 18 | maintainers = with lib.maintainers; [ mangoiv ]; 19 | mainProgram = "pol"; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /contrib/nix/shell.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs ? import { }, 3 | stdenv ? (env: if env.isLinux then pkgs.useMoldLinker env else env) pkgs.stdenv, 4 | ... 5 | }: 6 | pkgs.mkShell.override { inherit stdenv; } { 7 | nativeBuildInputs = 8 | [ 9 | pkgs.cargo 10 | pkgs.clippy 11 | pkgs.rust-analyzer 12 | pkgs.rustc 13 | pkgs.rustfmt 14 | 15 | pkgs.nixfmt-rfc-style 16 | 17 | pkgs.pkg-config 18 | pkgs.openssl 19 | ] 20 | ++ pkgs.lib.optionals stdenv.isDarwin [ 21 | pkgs.libiconv 22 | pkgs.darwin.apple_sdk.frameworks.SystemConfiguration 23 | ]; 24 | } 25 | -------------------------------------------------------------------------------- /examples/encoding_church.pol: -------------------------------------------------------------------------------- 1 | use "../std/codata/fun.pol" 2 | // Using the Church encoding we can represent a natural number using its 3 | // iteration principle. 4 | // 5 | // The iteration principle for the number "n" allows to construct, for any type "A", 6 | // an inhabitant of "A" by applying a function "s : A -> A" n-times to the 7 | // starting value "z : A". 8 | // 9 | // By defunctionalizing and refunctionalizing the type "Nat" you can observe how 10 | // the Church encoding corresponds to a program which defines an iteration principle 11 | // on Peano natural numbers. 12 | 13 | codata Nat { .iter(A: Type, z: A, s: A -> A): A } 14 | 15 | codef S(p: Nat): Nat { .iter(A, z, s) => s.ap(p.iter(A, z, s)) } 16 | 17 | codef Z: Nat { .iter(A, z, s) => z } 18 | -------------------------------------------------------------------------------- /examples/encoding_parigot.pol: -------------------------------------------------------------------------------- 1 | use "../std/codata/fun.pol" 2 | // The Parigot encoding combines the properties of the Church encoding and the Scott 3 | // encoding. 4 | // 5 | // The method "analyze" is the combination of the methods "iter" from the Church encoding 6 | // and the method "case" from the Scott encoding. We have access to both the predecessor 7 | // number itself and to the result of the recursive call. 8 | // 9 | // By defunctionalizing and refunctionalizing the type "Nat" you can observe how 10 | // the Parigot encoding can be understood as the refunctionalized version of Peano natural 11 | // numbers which implement a "analyze" method. 12 | 13 | codata Nat { .analyze(A: Type, z: A, s: Nat -> A -> A): A } 14 | 15 | codef S(p: Nat): Nat { .analyze(A, z, s) => s.ap(p).ap(p.analyze(A, z, s)) } 16 | 17 | codef Z: Nat { .analyze(A, z, s) => z } 18 | -------------------------------------------------------------------------------- /examples/encoding_scott.pol: -------------------------------------------------------------------------------- 1 | use "../std/codata/fun.pol" 2 | // Using the Scott encoding we can represent a natural number using its 3 | // pattern matching principle. 4 | // 5 | // The pattern matching principle for the number "n" allows to distinguish the zero 6 | // case from the successor case by either returning a value "z : A" if the number is zero, 7 | // or by applying a function "f : Nat -> A" to the predecessor of the number if it isn't zero. 8 | // 9 | // By defunctionalizing and refunctionalizing the type "Nat" you can observe how 10 | // the Scott encoding corresponds to a program which defines a pattern matching principle 11 | // on Peano natural numbers. 12 | 13 | codata Nat { .case(A: Type, z: A, s: Nat -> A): A } 14 | 15 | codef S(p: Nat): Nat { .case(A, z, s) => s.ap(p) } 16 | 17 | codef Z: Nat { .case(A, z, s) => z } 18 | -------------------------------------------------------------------------------- /examples/eq.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a b: Type, x: a): b, 3 | } 4 | 5 | infix _ -> _ := Fun(_,_) 6 | 7 | data Eq(a: Type, x y: a) { 8 | Refl(a: Type, x: a): Eq(a, x, x), 9 | } 10 | 11 | def Eq(a, x, y).sym(a: Type, x y: a): Eq(a, y, x) { Refl(a, x) => Refl(a, x) } 12 | 13 | def Eq(a, x, y).subst(a: Type, x y: a, p: a -> Type, prf: p.ap(a, Type, x)): p.ap(a, Type, y) { 14 | Refl(a, x) => prf, 15 | } 16 | 17 | def Eq(a, x, y).trans(a: Type, x y z: a, h: Eq(a, y, z)): Eq(a, x, z) { Refl(a, x) => h } 18 | 19 | def Eq(a, x, y).cong(a b: Type, x y: a, f: a -> b): Eq(b, f.ap(a, b, x), f.ap(a, b, y)) { 20 | Refl(a, x) => Refl(b, f.ap(a, b, x)), 21 | } 22 | -------------------------------------------------------------------------------- /examples/index.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Lawful Functor Class", 4 | "path": "functor.pol" 5 | }, 6 | { 7 | "name": "Martin-Löf Equality Type", 8 | "path": "eq.pol" 9 | }, 10 | { 11 | "name": "Set Interface", 12 | "path": "set.pol" 13 | }, 14 | { 15 | "name": "STLC Type Soundness", 16 | "path": "stlc.pol" 17 | }, 18 | { 19 | "name": "Strong Existentials Demystified", 20 | "path": "strong_existentials.pol" 21 | }, 22 | { 23 | "name": "Tutorial", 24 | "path": "tutorial.pol" 25 | }, 26 | { 27 | "name": "Π Is Not Built-In", 28 | "path": "pi.pol" 29 | }, 30 | { 31 | "name": "λ-Encoding: Church", 32 | "path": "encoding_church.pol" 33 | }, 34 | { 35 | "name": "λ-Encoding: Fu & Stump", 36 | "path": "encoding_fu_stump.pol" 37 | }, 38 | { 39 | "name": "λ-Encoding: Parigot", 40 | "path": "encoding_parigot.pol" 41 | }, 42 | { 43 | "name": "λ-Encoding: Scott", 44 | "path": "encoding_scott.pol" 45 | } 46 | ] 47 | -------------------------------------------------------------------------------- /examples/pi.pol: -------------------------------------------------------------------------------- 1 | /// The non-dependent function type. 2 | codata Fun(a b: Type) { 3 | Fun(a, b).ap(a b: Type, x: a): b, 4 | } 5 | 6 | infix _ -> _ := Fun(_,_) 7 | 8 | /// The dependent function type. 9 | codata Π(a: Type, p: a -> Type) { 10 | Π(a, p).pi_elim(a: Type, p: a -> Type, x: a): p.ap(a, Type, x), 11 | } 12 | 13 | /// The dependent sum type. 14 | data Σ(a: Type, p: a -> Type) { 15 | Exists(a: Type, p: a -> Type, x: a, prf: p.ap(a, Type, x)): Σ(a, p), 16 | } 17 | 18 | data Sum(a b: Type) { 19 | /// The left injection into a sum. 20 | Inl(a b: Type, x: a): Sum(a, b), 21 | /// The right injection into a sum. 22 | Inr(a b: Type, x: b): Sum(a, b), 23 | } 24 | 25 | codata Pair(a b: Type) { 26 | Pair(a, b).π₁(a b: Type): a, 27 | Pair(a, b).π₂(a b: Type): b, 28 | } 29 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs.flake-parts.url = "github:hercules-ci/flake-parts"; 3 | inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 4 | 5 | outputs = 6 | inputs: 7 | inputs.flake-parts.lib.mkFlake { inherit inputs; } { 8 | systems = [ 9 | "x86_64-linux" 10 | "aarch64-linux" 11 | "x86_64-darwin" 12 | "aarch64-darwin" 13 | ]; 14 | perSystem = 15 | { pkgs, config, ... }: 16 | { 17 | devShells.default = import ./contrib/nix/shell.nix { inherit pkgs; }; 18 | packages = import ./contrib/nix/default.nix { inherit pkgs; } // { 19 | default = config.packages.polarity; 20 | }; 21 | formatter = pkgs.nixfmt-rfc-style; 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /lang/ast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ast" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | # fancy error messages 16 | miette = { workspace = true } 17 | thiserror = "1" 18 | # url (for file locations) 19 | url = "2.5.0" 20 | # ignoring fields when deriving traits (e.g. Eq, Hash) 21 | derivative = "2" 22 | # big integers 23 | num-bigint = "0.4" 24 | # lazy static 25 | fxhash = "0.2.1" 26 | # prettyprinting 27 | pretty = { version = "0.11", features = ["termcolor"] } 28 | # workspace members 29 | miette_util = { path = "../miette_util" } 30 | printer = { path = "../printer" } 31 | -------------------------------------------------------------------------------- /lang/ast/src/ctx/map_idx.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | pub trait MapIdxExt { 4 | fn map_idx U>(&self, f: F) -> MapIdx<'_, T, U, F>; 5 | } 6 | 7 | impl MapIdxExt for Vec> { 8 | fn map_idx U>(&self, f: F) -> MapIdx<'_, T, U, F> { 9 | MapIdx { inner: self, f } 10 | } 11 | } 12 | 13 | pub struct MapIdx<'a, T, U, F: Fn(Idx, &T) -> U> { 14 | inner: &'a Vec>, 15 | f: F, 16 | } 17 | 18 | impl U> MapIdx<'_, T, U, F> { 19 | pub fn collect(self) -> Vec> { 20 | self.inner 21 | .iter() 22 | .enumerate() 23 | .map(|(fst, stack)| { 24 | stack 25 | .iter() 26 | .enumerate() 27 | .map(|(snd, x)| { 28 | (self.f)( 29 | Idx { fst: self.inner.len() - 1 - fst, snd: stack.len() - 1 - snd }, 30 | x, 31 | ) 32 | }) 33 | .collect() 34 | }) 35 | .collect() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lang/ast/src/ctx/mod.rs: -------------------------------------------------------------------------------- 1 | mod def; 2 | mod levels; 3 | pub mod map_idx; 4 | pub mod values; 5 | 6 | pub use def::*; 7 | pub use levels::*; 8 | -------------------------------------------------------------------------------- /lang/ast/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ctx; 2 | mod decls; 3 | mod exp; 4 | mod ident; 5 | pub mod traits; 6 | 7 | pub use decls::*; 8 | pub use exp::*; 9 | pub use ident::*; 10 | pub use traits::*; 11 | 12 | pub type HashMap = std::collections::HashMap; 13 | pub type HashSet = fxhash::FxHashSet; 14 | -------------------------------------------------------------------------------- /lang/ast/src/traits/contains_metavars.rs: -------------------------------------------------------------------------------- 1 | pub trait ContainsMetaVars { 2 | /// Whether the expression or any inferred type contains metavariables 3 | fn contains_metavars(&self) -> bool; 4 | } 5 | 6 | impl ContainsMetaVars for Vec { 7 | fn contains_metavars(&self) -> bool { 8 | self.iter().any(|x| x.contains_metavars()) 9 | } 10 | } 11 | 12 | impl ContainsMetaVars for Box { 13 | fn contains_metavars(&self) -> bool { 14 | self.as_ref().contains_metavars() 15 | } 16 | } 17 | 18 | impl ContainsMetaVars for Option { 19 | fn contains_metavars(&self) -> bool { 20 | self.as_ref().is_some_and(|x| x.contains_metavars()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lang/ast/src/traits/has_span.rs: -------------------------------------------------------------------------------- 1 | use miette_util::codespan::Span; 2 | 3 | /// Trait for syntactic entities which have a source-code span. 4 | /// 5 | /// The function `span()` should return `Some(span)` for every entity which 6 | /// is the result of parsing or lowering, but might return `None` for 7 | /// expressions which were annotated during elaboration, or which are the 8 | /// result of some code transformation. 9 | pub trait HasSpan { 10 | /// Return the source code span of the entity. 11 | fn span(&self) -> Option; 12 | } 13 | 14 | impl HasSpan for Option { 15 | fn span(&self) -> Option { 16 | *self 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lang/ast/src/traits/has_type.rs: -------------------------------------------------------------------------------- 1 | use crate::exp::Exp; 2 | 3 | /// Trait for expressions which have a type. 4 | /// 5 | /// The function `typ()` itself should not perform any non-trivial computation. 6 | /// You should first run elaboration on an expression before you call `typ()` on it, 7 | /// otherwise the function is not guaranteed to return a result. 8 | pub trait HasType { 9 | /// Return the type of the expression. 10 | fn typ(&self) -> Option>; 11 | } 12 | -------------------------------------------------------------------------------- /lang/ast/src/traits/mod.rs: -------------------------------------------------------------------------------- 1 | mod contains_metavars; 2 | mod has_span; 3 | mod has_type; 4 | mod occurs; 5 | pub mod rename; 6 | mod shift; 7 | pub mod subst; 8 | mod zonk; 9 | 10 | pub use contains_metavars::*; 11 | pub use has_span::*; 12 | pub use has_type::*; 13 | pub use occurs::*; 14 | pub use shift::*; 15 | pub use subst::*; 16 | pub use zonk::*; 17 | -------------------------------------------------------------------------------- /lang/ast/src/traits/zonk.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | use crate::{HashMap, MetaVar, MetaVarState}; 4 | 5 | /// Insert metavariable solutions in all holes in the AST 6 | pub trait Zonk { 7 | fn zonk(&mut self, meta_vars: &HashMap) -> Result<(), ZonkError>; 8 | } 9 | 10 | impl Zonk for Option { 11 | fn zonk(&mut self, meta_vars: &HashMap) -> Result<(), ZonkError> { 12 | if let Some(inner) = self { 13 | inner.zonk(meta_vars)?; 14 | } 15 | Ok(()) 16 | } 17 | } 18 | 19 | impl Zonk for Box { 20 | fn zonk(&mut self, meta_vars: &HashMap) -> Result<(), ZonkError> { 21 | self.as_mut().zonk(meta_vars) 22 | } 23 | } 24 | 25 | impl Zonk for Vec { 26 | fn zonk(&mut self, meta_vars: &HashMap) -> Result<(), ZonkError> { 27 | for item in self { 28 | item.zonk(meta_vars)?; 29 | } 30 | Ok(()) 31 | } 32 | } 33 | 34 | #[derive(Debug, Error)] 35 | pub enum ZonkError { 36 | #[error("Unbound meta-variable: ?{}", _0.id)] 37 | UnboundMetaVar(MetaVar), 38 | } 39 | -------------------------------------------------------------------------------- /lang/backend/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "backend" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | homepage.workspace = true 9 | repository.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | # ir structures 14 | url = { workspace = true } 15 | # error handling 16 | miette = { workspace = true } 17 | thiserror = { workspace = true } 18 | # workspace dependencies 19 | ast = { path = "../ast" } 20 | printer = { path = "../printer" } 21 | -------------------------------------------------------------------------------- /lang/backend/src/ast2ir/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod decls; 2 | pub mod exprs; 3 | pub mod traits; 4 | -------------------------------------------------------------------------------- /lang/backend/src/ast2ir/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::result::BackendError; 2 | 3 | /// Convert AST to IR (intermediate representation) 4 | /// 5 | /// Takes into account the erasure information annotated in the AST. 6 | /// Nodes annotated with `erased: true` won't occur in the generated IR. 7 | pub trait ToIR { 8 | type Target; 9 | 10 | fn to_ir(&self) -> Result; 11 | } 12 | 13 | impl ToIR for Vec { 14 | type Target = Vec; 15 | 16 | fn to_ir(&self) -> Result { 17 | self.iter().map(|x| x.to_ir()).collect() 18 | } 19 | } 20 | 21 | impl ToIR for Option { 22 | type Target = Option; 23 | 24 | fn to_ir(&self) -> Result { 25 | match self { 26 | Some(x) => Ok(Some(x.to_ir()?)), 27 | None => Ok(None), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lang/backend/src/ir/mod.rs: -------------------------------------------------------------------------------- 1 | //! High-level intermediate respresentation of the AST after erasure. 2 | //! This representation is shared between any compiler backends and hence can only make few assumptions about the compilation target. 3 | 4 | pub mod decls; 5 | pub mod exprs; 6 | 7 | pub use decls::*; 8 | pub use exprs::*; 9 | -------------------------------------------------------------------------------- /lang/backend/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod ast2ir; 2 | pub mod ir; 3 | pub mod result; 4 | -------------------------------------------------------------------------------- /lang/backend/src/result.rs: -------------------------------------------------------------------------------- 1 | use miette::Diagnostic; 2 | use thiserror::Error; 3 | 4 | #[derive(Error, Debug, Diagnostic, Clone)] 5 | pub enum BackendError { 6 | #[error("Impossible: {0}")] 7 | Impossible(String), 8 | } 9 | -------------------------------------------------------------------------------- /lang/docs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "docs" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | homepage.workspace = true 9 | repository.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | pretty = { workspace = true } 14 | opener = "0.5" 15 | askama = "0.12.1" 16 | askama_escape = "0.10.3" 17 | comrak = "0.32" 18 | 19 | # workspace members 20 | ast = { path = "../ast" } 21 | printer = { path = "../printer" } 22 | driver = { path = "../driver" } 23 | # url (for file locations) 24 | url = "2.5.0" 25 | -------------------------------------------------------------------------------- /lang/docs/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod doc; 2 | pub mod generate; 3 | pub mod generate_docs; 4 | pub mod printer; 5 | pub mod sidebar; 6 | pub mod util; 7 | 8 | mod render; 9 | pub use doc::write_html; 10 | pub use printer::*; 11 | pub use sidebar::generate_html_from_paths; 12 | pub use util::get_target_path; 13 | pub use util::open; 14 | pub use util::trim_windows_path_prefix; 15 | -------------------------------------------------------------------------------- /lang/docs/src/printer.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use printer::{Alloc, Print, PrintCfg}; 4 | 5 | use crate::render; 6 | 7 | pub fn print_html(pr: P, cfg: &PrintCfg, out: &mut W) -> io::Result<()> { 8 | let alloc = Alloc::new(); 9 | let doc_builder = pr.print(cfg, &alloc); 10 | doc_builder.render_raw(cfg.width, &mut render::RenderHtml::new(out)) 11 | } 12 | 13 | pub fn print_html_to_string(pr: P, cfg: Option<&PrintCfg>) -> String { 14 | let mut buf = Vec::new(); 15 | let def = PrintCfg::default(); 16 | let cfg = cfg.unwrap_or(&def); 17 | print_html(pr, cfg, &mut buf).expect("Failed to print to string"); 18 | String::from_utf8(buf).expect("Failed to convert Vec to String") 19 | } 20 | -------------------------------------------------------------------------------- /lang/docs/src/render/mod.rs: -------------------------------------------------------------------------------- 1 | mod html; 2 | 3 | pub use html::*; 4 | -------------------------------------------------------------------------------- /lang/docs/templates/codata.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | codata {{name}}{{attr}} {{typ}} 6 |
7 |
8 |
9 | {{doc}} 10 |
11 |
12 | 13 | {{body}} 14 | 15 |
16 |
-------------------------------------------------------------------------------- /lang/docs/templates/codef.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | codef {{name}}{{params}}: {{typ}} 6 |
7 |
8 | 9 |
10 |
11 |
12 | {{doc}} 13 |
14 | 19 |
-------------------------------------------------------------------------------- /lang/docs/templates/data.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | data {{name}}{{attr}}{{typ}} 6 |
7 |
8 |
9 | {{doc}} 10 |
11 |
12 | 13 | {{body}} 14 | 15 |
16 |
-------------------------------------------------------------------------------- /lang/docs/templates/def.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | def {{self_param}}.{{name}}{{params}}: {{typ}} 6 |
7 |
8 | 9 |
10 |
11 |
12 | {{doc}} 13 |
14 | 19 |
-------------------------------------------------------------------------------- /lang/docs/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{title}} 7 | 8 | 9 | 10 | 16 |
{{code}}
17 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /lang/docs/templates/infix.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | infix _ {{lhs}} _ := {{rhs}}(_,_) 5 |
6 |
7 |
8 | {{doc}} 9 |
10 |
-------------------------------------------------------------------------------- /lang/docs/templates/let.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | let {{name}}: {{params}}{{typ}} 6 |
7 |
8 | 9 |
10 |
11 |
12 | {{doc}} 13 |
14 | 19 |
-------------------------------------------------------------------------------- /lang/docs/templates/module.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{title}}

4 |
5 | {{content}} 6 |
7 | -------------------------------------------------------------------------------- /lang/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | # async 16 | async-trait = "0.1" 17 | # adressing symbols 18 | url = { workspace = true } 19 | lsp-types = { workspace = true } 20 | # index of source code intervals 21 | rust-lapper = "1" 22 | # text rope 23 | ropey = "1" 24 | # fancy error messages 25 | miette = { workspace = true } 26 | thiserror = { workspace = true } 27 | # logging 28 | log = { workspace = true } 29 | # workspace members 30 | ast = { path = "../ast" } 31 | lowering = { path = "../lowering" } 32 | elaborator = { path = "../elaborator" } 33 | printer = { path = "../printer" } 34 | parser = { path = "../parser" } 35 | transformations = { path = "../transformations" } 36 | backend = { path = "../backend" } 37 | miette_util = { path = "../miette_util" } 38 | -------------------------------------------------------------------------------- /lang/driver/src/asserts.rs: -------------------------------------------------------------------------------- 1 | use crate::database::Database; 2 | 3 | const _: () = { 4 | fn assert_send() {} 5 | fn assert_sync() {} 6 | 7 | // RFC 2056 8 | fn assert_all() { 9 | assert_send::(); 10 | assert_sync::(); 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /lang/driver/src/edit.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Range; 2 | 3 | use miette_util::codespan::Span; 4 | use ropey::Rope; 5 | use url::Url; 6 | 7 | use crate::database::Database; 8 | 9 | #[derive(Ord, PartialOrd, Eq, PartialEq)] 10 | pub struct Edit { 11 | pub span: Span, 12 | pub text: String, 13 | } 14 | 15 | impl Database { 16 | pub fn edited(&self, uri: &Url, mut edits: Vec) -> Rope { 17 | let source = &self.files.get_even_if_stale(uri).unwrap().source; 18 | 19 | let mut rope = Rope::from_str(source); 20 | 21 | edits.sort(); 22 | 23 | for edit in edits.iter().rev() { 24 | let remove_range = edit.span.as_range(); 25 | let char_range = 26 | rope.byte_to_char(remove_range.start)..rope.byte_to_char(remove_range.end); 27 | rope.remove(char_range); 28 | let char_idx = rope.byte_to_char(edit.span.start.0 as usize); 29 | rope.insert(char_idx, &edit.text); 30 | } 31 | 32 | rope 33 | } 34 | } 35 | 36 | trait SpanAsRange { 37 | fn as_range(&self) -> Range; 38 | } 39 | 40 | impl SpanAsRange for Span { 41 | fn as_range(&self) -> Range { 42 | self.start.0 as usize..self.end.0 as usize 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lang/driver/src/info/data.rs: -------------------------------------------------------------------------------- 1 | use printer::Print; 2 | 3 | use ast::ctx::values::{Binder as TypeCtxBinder, Binding, TypeCtx}; 4 | 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct Ctx { 7 | pub bound: Vec>, 8 | } 9 | 10 | #[derive(Debug, Clone, PartialEq, Eq)] 11 | pub enum Binder { 12 | Var { name: String, typ: String }, 13 | Wildcard { typ: String }, 14 | } 15 | 16 | impl From for Ctx { 17 | fn from(ctx: TypeCtx) -> Self { 18 | let bound = 19 | ctx.bound.into_iter().map(|tel| tel.into_iter().map(Into::into).collect()).collect(); 20 | Ctx { bound } 21 | } 22 | } 23 | 24 | impl From> for Binder { 25 | fn from(binder: TypeCtxBinder) -> Self { 26 | match binder.name { 27 | ast::VarBind::Var { id, .. } => { 28 | Binder::Var { name: id, typ: binder.content.typ.print_to_string(None) } 29 | } 30 | ast::VarBind::Wildcard { .. } => { 31 | Binder::Wildcard { typ: binder.content.typ.print_to_string(None) } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lang/driver/src/info/item.rs: -------------------------------------------------------------------------------- 1 | // Item 2 | // 3 | // 4 | 5 | #[derive(PartialEq, Eq, Clone)] 6 | pub enum Item { 7 | Data(String), 8 | Codata(String), 9 | Def { name: String, type_name: String }, 10 | Codef { name: String, type_name: String }, 11 | } 12 | 13 | impl Item { 14 | pub fn type_name(&self) -> &str { 15 | match self { 16 | Item::Data(name) => name, 17 | Item::Codata(name) => name, 18 | Item::Def { type_name, .. } => type_name, 19 | Item::Codef { type_name, .. } => type_name, 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lang/driver/src/info/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module provides utilities which are used by the language 2 | //! server for the type-on-hover and code-action features. 3 | 4 | mod collect; 5 | mod data; 6 | mod item; 7 | mod lookup; 8 | 9 | pub use collect::*; 10 | pub use data::*; 11 | pub use item::*; 12 | -------------------------------------------------------------------------------- /lang/driver/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use result::Error; 2 | 3 | mod asserts; 4 | mod cache; 5 | mod codespan; 6 | mod database; 7 | mod dependency_graph; 8 | mod edit; 9 | mod fs; 10 | mod info; 11 | mod lift; 12 | pub mod paths; 13 | mod result; 14 | mod spans; 15 | mod xfunc; 16 | 17 | pub use database::Database; 18 | 19 | pub use edit::*; 20 | pub use fs::*; 21 | pub use info::*; 22 | pub use paths::*; 23 | pub use result::DriverError; 24 | pub use xfunc::*; 25 | -------------------------------------------------------------------------------- /lang/driver/src/paths.rs: -------------------------------------------------------------------------------- 1 | pub const TARGET_PATH: &str = "target_pol/"; 2 | 3 | pub const IR_PATH: &str = "target_pol/ir/"; 4 | 5 | pub const DOCS_PATH: &str = "target_pol/docs/"; 6 | 7 | pub const CSS_PATH: &str = "target_pol/docs/style.css"; 8 | 9 | pub const CSS_TEMPLATE_PATH: &str = include_str!("../../docs/templates/style.css"); 10 | -------------------------------------------------------------------------------- /lang/elaborator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "elaborator" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | miette = { workspace = true } 16 | thiserror = { workspace = true } 17 | derivative = { workspace = true } 18 | pretty = { workspace = true } 19 | log = { workspace = true } 20 | url = { workspace = true } 21 | 22 | # workspace members 23 | ast = { path = "../ast" } 24 | printer = { path = "../printer" } 25 | miette_util = { path = "../miette_util" } 26 | -------------------------------------------------------------------------------- /lang/elaborator/src/index_unification/constraints.rs: -------------------------------------------------------------------------------- 1 | //! This module defines the language of constraints that can be solved by the constraint solver. 2 | use ast::{Args, Exp}; 3 | use printer::Print; 4 | 5 | /// A constraint that can be solved by the constraint solver. 6 | #[derive(Debug, Clone, Eq, PartialEq, Hash)] 7 | pub enum Constraint { 8 | /// An equality constraint between two expressions. 9 | Equality { lhs: Box, rhs: Box }, 10 | /// An equality constraint between two argument lists. 11 | EqualityArgs { lhs: Args, rhs: Args }, 12 | } 13 | 14 | impl Print for Constraint { 15 | fn print<'a>( 16 | &'a self, 17 | cfg: &printer::PrintCfg, 18 | alloc: &'a printer::Alloc<'a>, 19 | ) -> printer::Builder<'a> { 20 | match self { 21 | Constraint::Equality { lhs, rhs } => { 22 | lhs.print(cfg, alloc).append(" = ").append(rhs.print(cfg, alloc)) 23 | } 24 | Constraint::EqualityArgs { lhs, rhs } => { 25 | lhs.print(cfg, alloc).append(" = ").append(rhs.print(cfg, alloc)) 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lang/elaborator/src/index_unification/dec.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | pub enum Dec { 4 | Yes(Y), 5 | No, 6 | } 7 | 8 | pub use Dec::*; 9 | 10 | impl fmt::Debug for Dec { 11 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 12 | match self { 13 | Self::Yes(arg) => f.debug_tuple("Yes").field(arg).finish(), 14 | Self::No => f.debug_tuple("No").finish(), 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lang/elaborator/src/index_unification/mod.rs: -------------------------------------------------------------------------------- 1 | //! Index unification for dependent pattern matching 2 | //! 3 | //! To understand what index unification does on a high level, consider the following example: 4 | //! 5 | //! ```pol 6 | //! data Bool { T, F } 7 | //! data Nat { Z, S(x: Nat) } 8 | //! 9 | //! data BoolRep(b: Bool) { 10 | //! TRep : BoolRep(T), 11 | //! FRep : BoolRep(F), 12 | //! } 13 | //! 14 | //! def BoolRep(T).foo : Nat { 15 | //! TRep => 0, 16 | //! FRep absurd 17 | //! } 18 | //! ``` 19 | //! 20 | //! Here, `BoolRep` is an indexed data type that lifts a Boolean value to the type level. 21 | //! The definition `foo` takes a `BoolRep(T)` and returns a `Nat`. 22 | //! The unification algorithm in this module verifies that `TRep` is the only possible constructor based on the type index `b = T`. 23 | //! 24 | //! More generally, given a pattern match, for each clause, the algorithm equates the type indices of the constructor definition with the type indices of the scrutinee. 25 | //! This equation is being decomposed into a set of constraints that are then solved by the unification algorithm. 26 | //! The result of unification is a substitution that equalizes these type indices. 27 | //! The elaborator will apply this substitution to the context, the right-hand side and the type of the clause before proceeding to typecheck the clause. 28 | //! 29 | //! Copattern matching is handled analogously. 30 | 31 | pub mod constraints; 32 | pub mod dec; 33 | pub mod unify; 34 | -------------------------------------------------------------------------------- /lang/elaborator/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod conversion_checking; 2 | pub mod index_unification; 3 | pub mod normalizer; 4 | pub mod result; 5 | pub mod typechecker; 6 | 7 | pub use typechecker::type_info_table::ModuleTypeInfoTable; 8 | pub use typechecker::type_info_table::TypeInfoTable; 9 | pub use typechecker::type_info_table::build::build_type_info_table; 10 | -------------------------------------------------------------------------------- /lang/elaborator/src/normalizer/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod env; 2 | mod eval; 3 | pub mod normalize; 4 | pub mod val; 5 | -------------------------------------------------------------------------------- /lang/elaborator/src/normalizer/normalize.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::normalizer::val::ReadBack; 4 | use crate::{TypeInfoTable, result::*}; 5 | 6 | use super::env::Env; 7 | use super::eval::*; 8 | 9 | pub trait Normalize { 10 | type Nf; 11 | 12 | fn normalize(&self, info_table: &Rc, env: &mut Env) -> TcResult; 13 | 14 | fn normalize_in_empty_env(&self, info_table: &Rc) -> TcResult { 15 | self.normalize(info_table, &mut Env::empty()) 16 | } 17 | } 18 | 19 | impl Normalize for T 20 | where 21 | T: Eval, 22 | ::Val: ReadBack, 23 | { 24 | type Nf = <::Val as ReadBack>::Nf; 25 | 26 | fn normalize(&self, info_table: &Rc, env: &mut Env) -> TcResult { 27 | let val = self.eval(info_table, env)?; 28 | val.read_back(info_table) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/decls/global_let.rs: -------------------------------------------------------------------------------- 1 | //! Checking the well-formedness of global let-bound expressions 2 | 3 | use log::trace; 4 | 5 | use ast::*; 6 | 7 | use super::CheckToplevel; 8 | use crate::normalizer::env::ToEnv; 9 | use crate::normalizer::normalize::Normalize; 10 | use crate::result::TcResult; 11 | use crate::typechecker::erasure; 12 | use crate::typechecker::{ 13 | ctx::Ctx, 14 | exprs::{CheckInfer, InferTelescope}, 15 | }; 16 | 17 | impl CheckToplevel for Let { 18 | fn check_wf(&self, ctx: &mut Ctx) -> TcResult { 19 | trace!("Checking well-formedness of global let: {}", self.name); 20 | 21 | let Let { span, doc, name, attr, params, typ, body } = self; 22 | 23 | params.infer_telescope(ctx, |ctx, mut params_out| { 24 | let typ_out = typ.infer(ctx)?; 25 | let typ_nf = typ.normalize(&ctx.type_info_table, &mut ctx.env())?; 26 | let body_out = body.check(ctx, &typ_nf)?; 27 | 28 | erasure::mark_erased_params(&mut params_out); 29 | 30 | Ok(Let { 31 | span: *span, 32 | doc: doc.clone(), 33 | name: name.clone(), 34 | attr: attr.clone(), 35 | params: params_out, 36 | typ: typ_out, 37 | body: body_out, 38 | }) 39 | }) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/decls/infix_declaration.rs: -------------------------------------------------------------------------------- 1 | use ast::Infix; 2 | 3 | use super::CheckToplevel; 4 | 5 | impl CheckToplevel for Infix { 6 | fn check_wf(&self, _ctx: &mut crate::typechecker::ctx::Ctx) -> crate::result::TcResult { 7 | Ok(self.clone()) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/exprs/anno.rs: -------------------------------------------------------------------------------- 1 | //! Bidirectional type checker 2 | 3 | use crate::conversion_checking::convert; 4 | use crate::normalizer::env::ToEnv; 5 | use crate::normalizer::normalize::Normalize; 6 | use ast::*; 7 | 8 | use super::CheckInfer; 9 | use super::{super::ctx::*, ExpectType}; 10 | use crate::result::TcResult; 11 | 12 | impl CheckInfer for Anno { 13 | fn check(&self, ctx: &mut Ctx, t: &Exp) -> TcResult { 14 | let inferred_term = self.infer(ctx)?; 15 | let inferred_typ = inferred_term.expect_typ()?; 16 | convert(&ctx.vars, &mut ctx.meta_vars, inferred_typ, t, &self.span())?; 17 | Ok(inferred_term) 18 | } 19 | 20 | /// The *inference* rule for type annotations is: 21 | /// ```text 22 | /// P, Γ ⊢ τ ⇐ Type 23 | /// P, Γ ⊢ τ ▷ τ' 24 | /// P, Γ ⊢ e ⇐ τ' 25 | /// ────────────────────── 26 | /// P, Γ ⊢ (e : τ) ⇒ τ' 27 | /// ``` 28 | fn infer(&self, ctx: &mut Ctx) -> TcResult { 29 | let Anno { span, exp, typ, .. } = self; 30 | let typ_out = typ.check(ctx, &Box::new(TypeUniv::new().into()))?; 31 | let typ_nf = typ.normalize(&ctx.type_info_table, &mut ctx.env())?; 32 | let exp_out = (**exp).check(ctx, &typ_nf)?; 33 | Ok(Anno { 34 | span: *span, 35 | exp: Box::new(exp_out), 36 | typ: typ_out, 37 | normalized_type: Some(typ_nf), 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/exprs/type_univ.rs: -------------------------------------------------------------------------------- 1 | //! Bidirectional type checker 2 | 3 | use ast::*; 4 | 5 | use super::super::ctx::*; 6 | use super::CheckInfer; 7 | use crate::conversion_checking::convert; 8 | use crate::result::TcResult; 9 | 10 | // TypeUniv 11 | // 12 | // 13 | 14 | impl CheckInfer for TypeUniv { 15 | /// The *checking* rule for the type universe is: 16 | /// ```text 17 | /// P, Γ ⊢ τ ≃ Type 18 | /// ────────────────── 19 | /// P, Γ ⊢ Type ⇐ τ 20 | /// ``` 21 | fn check(&self, ctx: &mut Ctx, t: &Exp) -> TcResult { 22 | convert(&ctx.vars, &mut ctx.meta_vars, Box::new(TypeUniv::new().into()), t, &self.span())?; 23 | Ok(self.clone()) 24 | } 25 | 26 | /// The *inference* rule for the type universe is: 27 | /// ```text 28 | /// ───────────────────── 29 | /// P, Γ ⊢ Type ⇒ Type 30 | /// ``` 31 | /// Note: The type universe is impredicative and the theory 32 | /// therefore inconsistent. 33 | fn infer(&self, _ctx: &mut Ctx) -> TcResult { 34 | Ok(self.clone()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/exprs/variable.rs: -------------------------------------------------------------------------------- 1 | //! Bidirectional type checking for variables 2 | 3 | use ast::*; 4 | 5 | use super::super::ctx::*; 6 | use super::{CheckInfer, ExpectType}; 7 | use crate::conversion_checking::convert; 8 | use crate::result::TcResult; 9 | 10 | impl CheckInfer for Variable { 11 | /// The *checking* rule for variables is: 12 | /// ```text 13 | /// P, Γ ⊢ x ⇒ τ 14 | /// P, Γ ⊢ τ ≃ σ 15 | /// ─────────────── 16 | /// P, Γ ⊢ x ⇐ σ 17 | /// ``` 18 | fn check(&self, ctx: &mut Ctx, t: &Exp) -> TcResult { 19 | let inferred_term = self.infer(ctx)?; 20 | let inferred_typ = inferred_term.expect_typ()?; 21 | convert(&ctx.vars, &mut ctx.meta_vars, inferred_typ, t, &self.span())?; 22 | Ok(inferred_term) 23 | } 24 | 25 | /// The *inference* rule for variables is: 26 | /// ```text 27 | /// Γ(x) = τ 28 | /// ─────────────── 29 | /// P, Γ ⊢ x ⇒ τ 30 | /// ``` 31 | fn infer(&self, ctx: &mut Ctx) -> TcResult { 32 | let Variable { span, idx, name, .. } = self; 33 | let typ_nf = ctx.lookup(*idx); 34 | Ok(Variable { span: *span, idx: *idx, name: name.clone(), inferred_type: Some(typ_nf) }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ctx; 2 | pub mod decls; 3 | mod erasure; 4 | pub mod exprs; 5 | pub mod type_info_table; 6 | pub mod util; 7 | 8 | pub use crate::result::TypeError; 9 | pub use decls::check_with_lookup_table; 10 | -------------------------------------------------------------------------------- /lang/elaborator/src/typechecker/util.rs: -------------------------------------------------------------------------------- 1 | use ast::ctx::LevelCtx; 2 | use ast::*; 3 | 4 | use crate::result::TcResult; 5 | 6 | use super::TypeError; 7 | 8 | // Checks whether the codata type contains destructors with a self parameter 9 | pub fn uses_self(codata: &Codata) -> TcResult { 10 | for dtor in &codata.dtors { 11 | let mut ctx = 12 | LevelCtx::from(vec![dtor.params.params.clone(), vec![dtor.self_param.to_param()]]); 13 | if dtor.ret_typ.occurs_var(&mut ctx, Lvl { fst: 1, snd: 0 }) { 14 | return Ok(true); 15 | } 16 | } 17 | Ok(false) 18 | } 19 | 20 | pub trait ExpectTypApp { 21 | fn expect_typ_app(&self) -> TcResult; 22 | } 23 | 24 | impl ExpectTypApp for Exp { 25 | fn expect_typ_app(&self) -> TcResult { 26 | match self { 27 | Exp::TypCtor(TypCtor { span, name, args, is_bin_op }) => Ok(TypCtor { 28 | span: *span, 29 | name: name.clone(), 30 | args: args.clone(), 31 | is_bin_op: is_bin_op.clone(), 32 | }), 33 | _ => Err(TypeError::expected_typ_app(self).into()), 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lang/lowering/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lowering" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | miette = { workspace = true } 16 | thiserror = { workspace = true } 17 | # big integers 18 | num-bigint = { workspace = true } 19 | log = { workspace = true } 20 | url = { workspace = true } 21 | 22 | # workspace members 23 | printer = { path = "../printer" } 24 | parser = { path = "../parser" } 25 | ast = { path = "../ast" } 26 | miette_util = { path = "../miette_util" } 27 | -------------------------------------------------------------------------------- /lang/lowering/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod ctx; 2 | mod lower; 3 | mod result; 4 | mod symbol_table; 5 | 6 | use ast::{self}; 7 | use parser::cst; 8 | 9 | use crate::lower::Lower; 10 | 11 | pub use ctx::*; 12 | pub use result::*; 13 | pub use symbol_table::DeclMeta; 14 | pub use symbol_table::ModuleSymbolTable; 15 | pub use symbol_table::SymbolTable; 16 | pub use symbol_table::build::build_symbol_table; 17 | 18 | /// Lower a module 19 | /// 20 | /// The caller of this function needs to resolve module dependencies, lower all dependencies, and provide a symbol table with all symbols from these dependencies and the symbol table of the current module. 21 | pub fn lower_module_with_symbol_table( 22 | prg: &cst::decls::Module, 23 | symbol_table: &SymbolTable, 24 | ) -> LoweringResult { 25 | let mut ctx = Ctx::empty(prg.uri.clone(), symbol_table.clone()); 26 | 27 | let use_decls = prg.use_decls.lower(&mut ctx)?; 28 | let decls = prg.decls.lower(&mut ctx)?; 29 | 30 | Ok(ast::Module { uri: prg.uri.clone(), use_decls, decls, meta_vars: ctx.meta_vars }) 31 | } 32 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/decls/codefinition.rs: -------------------------------------------------------------------------------- 1 | use ast::IdBind; 2 | use miette_util::ToMiette; 3 | use parser::cst::{self}; 4 | 5 | use super::super::*; 6 | use super::lower_telescope; 7 | 8 | impl Lower for cst::decls::Codef { 9 | type Target = ast::Codef; 10 | 11 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 12 | log::trace!("Lowering codefinition: {}", self.name.id); 13 | 14 | let cst::decls::Codef { span, doc, name, attr, params, typ, cases, .. } = self; 15 | 16 | lower_telescope(params, ctx, |ctx, params| { 17 | let typ = typ.lower(ctx)?; 18 | let typ_ctor = typ 19 | .to_typctor() 20 | .ok_or(LoweringError::ExpectedTypCtor { span: span.to_miette() })?; 21 | Ok(ast::Codef { 22 | span: Some(*span), 23 | doc: doc.lower(ctx)?, 24 | name: IdBind { span: Some(name.span), id: name.id.clone() }, 25 | attr: attr.lower(ctx)?, 26 | params, 27 | typ: typ_ctor, 28 | cases: cases.lower(ctx)?, 29 | }) 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/decls/definition.rs: -------------------------------------------------------------------------------- 1 | use ast::IdBind; 2 | use parser::cst::{self}; 3 | 4 | use super::super::*; 5 | use super::lower_self_param; 6 | use super::lower_telescope; 7 | 8 | impl Lower for cst::decls::Def { 9 | type Target = ast::Def; 10 | 11 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 12 | log::trace!("Lowering definition: {}", self.name.id); 13 | 14 | let cst::decls::Def { span, doc, name, attr, params, scrutinee, ret_typ, cases } = self; 15 | 16 | let self_param: cst::decls::SelfParam = scrutinee.clone().into(); 17 | 18 | lower_telescope(params, ctx, |ctx, params| { 19 | let cases = cases.lower(ctx)?; 20 | lower_self_param(&self_param, ctx, |ctx, self_param| { 21 | Ok(ast::Def { 22 | span: Some(*span), 23 | doc: doc.lower(ctx)?, 24 | name: IdBind { span: Some(name.span), id: name.id.clone() }, 25 | attr: attr.lower(ctx)?, 26 | params, 27 | self_param, 28 | ret_typ: ret_typ.lower(ctx)?, 29 | cases, 30 | }) 31 | }) 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/decls/toplevel_let.rs: -------------------------------------------------------------------------------- 1 | use ast::IdBind; 2 | use parser::cst::{self}; 3 | 4 | use super::super::*; 5 | use super::lower_telescope; 6 | 7 | impl Lower for cst::decls::Let { 8 | type Target = ast::Let; 9 | 10 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 11 | log::trace!("Lowering top-level let: {}", self.name.id); 12 | 13 | let cst::decls::Let { span, doc, name, attr, params, typ, body } = self; 14 | 15 | lower_telescope(params, ctx, |ctx, params| { 16 | Ok(ast::Let { 17 | span: Some(*span), 18 | doc: doc.lower(ctx)?, 19 | name: IdBind { span: Some(name.span), id: name.id.clone() }, 20 | attr: attr.lower(ctx)?, 21 | params, 22 | typ: typ.lower(ctx)?, 23 | body: body.lower(ctx)?, 24 | }) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/anno.rs: -------------------------------------------------------------------------------- 1 | use parser::cst; 2 | 3 | use crate::{Ctx, LoweringResult, lower::Lower}; 4 | 5 | impl Lower for cst::exp::Anno { 6 | type Target = ast::Exp; 7 | 8 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 9 | let cst::exp::Anno { span, exp, typ } = self; 10 | Ok(ast::Anno { 11 | span: Some(*span), 12 | exp: exp.lower(ctx)?, 13 | typ: typ.lower(ctx)?, 14 | normalized_type: None, 15 | } 16 | .into()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/binop.rs: -------------------------------------------------------------------------------- 1 | use parser::cst::{self}; 2 | 3 | use crate::{Ctx, LoweringResult, lower::Lower}; 4 | 5 | impl Lower for cst::exp::BinOp { 6 | type Target = ast::Exp; 7 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 8 | let cst::exp::BinOp { span, operator, lhs, rhs } = self; 9 | 10 | let (id, _url) = ctx.symbol_table.lookup_operator(operator)?; 11 | let (_, name) = ctx.symbol_table.lookup(id)?; 12 | 13 | Ok(ast::TypCtor { 14 | span: Some(*span), 15 | name, 16 | args: ast::Args { 17 | args: vec![ 18 | ast::Arg::UnnamedArg { arg: lhs.lower(ctx)?, erased: false }, 19 | ast::Arg::UnnamedArg { arg: rhs.lower(ctx)?, erased: false }, 20 | ], 21 | }, 22 | is_bin_op: Some(operator.id.clone()), 23 | } 24 | .into()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/dot_call.rs: -------------------------------------------------------------------------------- 1 | use miette_util::ToMiette; 2 | use parser::cst; 3 | 4 | use crate::{Ctx, DeclMeta, LoweringError, LoweringResult, lower::Lower}; 5 | 6 | use super::args::lower_args; 7 | 8 | impl Lower for cst::exp::DotCall { 9 | type Target = ast::Exp; 10 | 11 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 12 | let cst::exp::DotCall { span, exp, name, args } = self; 13 | 14 | let (meta, name) = ctx.symbol_table.lookup(name)?; 15 | 16 | match meta.clone() { 17 | DeclMeta::Dtor { params, .. } => Ok(ast::Exp::DotCall(ast::DotCall { 18 | span: Some(*span), 19 | kind: ast::DotCallKind::Destructor, 20 | exp: exp.lower(ctx)?, 21 | name, 22 | args: lower_args(*span, args, params, ctx)?, 23 | inferred_type: None, 24 | })), 25 | DeclMeta::Def { params, .. } => Ok(ast::Exp::DotCall(ast::DotCall { 26 | span: Some(*span), 27 | kind: ast::DotCallKind::Definition, 28 | exp: exp.lower(ctx)?, 29 | name, 30 | args: lower_args(*span, args, params, ctx)?, 31 | inferred_type: None, 32 | })), 33 | _ => Err(LoweringError::CannotUseAsDotCall { name, span: span.to_miette() }.into()), 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/hole.rs: -------------------------------------------------------------------------------- 1 | use ast::Hole; 2 | use parser::cst; 3 | 4 | use crate::{Ctx, LoweringResult, lower::Lower}; 5 | 6 | impl Lower for cst::exp::HoleKind { 7 | type Target = ast::MetaVarKind; 8 | 9 | fn lower(&self, _ctx: &mut Ctx) -> LoweringResult { 10 | match self { 11 | cst::exp::HoleKind::MustSolve => Ok(ast::MetaVarKind::MustSolve), 12 | cst::exp::HoleKind::CanSolve => Ok(ast::MetaVarKind::CanSolve), 13 | } 14 | } 15 | } 16 | 17 | impl Lower for cst::exp::Hole { 18 | type Target = ast::Exp; 19 | 20 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 21 | let cst::exp::Hole { span, kind, .. } = self; 22 | let kind = kind.lower(ctx)?; 23 | let mv = ctx.fresh_metavar(Some(*span), kind); 24 | let args = ctx.subst_from_ctx(); 25 | Ok(Hole { 26 | span: Some(*span), 27 | kind, 28 | metavar: mv, 29 | inferred_type: None, 30 | inferred_ctx: None, 31 | args, 32 | solution: None, 33 | } 34 | .into()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/lam.rs: -------------------------------------------------------------------------------- 1 | use parser::cst; 2 | 3 | use crate::{Ctx, LoweringResult, lower::Lower}; 4 | 5 | impl Lower for cst::exp::Lam { 6 | type Target = ast::Exp; 7 | 8 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 9 | let cst::exp::Lam { span, case } = self; 10 | let comatch = cst::exp::Exp::LocalComatch(cst::exp::LocalComatch { 11 | span: *span, 12 | name: None, 13 | is_lambda_sugar: true, 14 | cases: vec![case.clone()], 15 | }); 16 | comatch.lower(ctx) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/local_comatch.rs: -------------------------------------------------------------------------------- 1 | use parser::cst; 2 | 3 | use crate::{Ctx, LoweringResult, lower::Lower}; 4 | 5 | use super::lower_telescope_inst; 6 | 7 | impl Lower for cst::exp::LocalComatch { 8 | type Target = ast::Exp; 9 | 10 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 11 | let cst::exp::LocalComatch { span, name, is_lambda_sugar, cases } = self; 12 | Ok(ast::LocalComatch { 13 | span: Some(*span), 14 | ctx: None, 15 | name: ctx.unique_label(name.to_owned(), span)?, 16 | is_lambda_sugar: *is_lambda_sugar, 17 | cases: cases.lower(ctx)?, 18 | inferred_type: None, 19 | } 20 | .into()) 21 | } 22 | } 23 | 24 | impl Lower for cst::exp::Case { 25 | type Target = ast::Case; 26 | 27 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 28 | let cst::exp::Case { span, pattern, body } = self; 29 | 30 | lower_telescope_inst(&pattern.params, ctx, |ctx, params| { 31 | let (_, name) = ctx.symbol_table.lookup(&pattern.name)?; 32 | Ok(ast::Case { 33 | span: Some(*span), 34 | pattern: ast::Pattern { 35 | span: Some(pattern.span), 36 | is_copattern: true, 37 | name, 38 | params, 39 | }, 40 | body: body.lower(ctx)?, 41 | }) 42 | }) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/local_let.rs: -------------------------------------------------------------------------------- 1 | use miette_util::ToMiette; 2 | use parser::cst; 3 | 4 | use crate::{LoweringError, lower::Lower}; 5 | 6 | impl Lower for cst::exp::LocalLet { 7 | type Target = ast::Exp; 8 | 9 | fn lower(&self, _ctx: &mut crate::Ctx) -> crate::LoweringResult { 10 | let cst::exp::LocalLet { span, .. } = self; 11 | Err(LoweringError::Impossible { 12 | message: "Lowering of local let expressions not implemented yet".to_string(), 13 | span: Some(span.to_miette()), 14 | } 15 | .into()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/exp/parens.rs: -------------------------------------------------------------------------------- 1 | use parser::cst; 2 | 3 | use crate::lower::Lower; 4 | 5 | impl Lower for cst::exp::Parens { 6 | type Target = ast::Exp; 7 | 8 | fn lower(&self, ctx: &mut crate::Ctx) -> crate::LoweringResult { 9 | let e = self.exp.lower(ctx)?; 10 | Ok(*e) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lang/lowering/src/lower/mod.rs: -------------------------------------------------------------------------------- 1 | use super::ctx::*; 2 | use super::result::*; 3 | mod decls; 4 | mod exp; 5 | 6 | pub trait Lower { 7 | type Target; 8 | 9 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult; 10 | } 11 | 12 | impl Lower for Option { 13 | type Target = Option; 14 | 15 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 16 | self.as_ref().map(|x| x.lower(ctx)).transpose() 17 | } 18 | } 19 | 20 | impl Lower for Vec { 21 | type Target = Vec; 22 | 23 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 24 | self.iter().map(|x| x.lower(ctx)).collect() 25 | } 26 | } 27 | 28 | impl Lower for Box { 29 | type Target = Box; 30 | 31 | fn lower(&self, ctx: &mut Ctx) -> LoweringResult { 32 | Ok(Box::new((**self).lower(ctx)?)) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lang/lowering/src/symbol_table/mod.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use ast::HashMap; 4 | use decls::*; 5 | use ident::Ident; 6 | use parser::cst::{ident::Operator, *}; 7 | use url::Url; 8 | 9 | pub mod build; 10 | pub mod lookup; 11 | 12 | /// The symbol table for a single module. 13 | #[derive(Debug, Default, Clone)] 14 | pub struct ModuleSymbolTable { 15 | /// The mapping of identifiers to their metadata 16 | pub idents: HashMap, 17 | /// The mapping of operators to their definition 18 | pub infix_ops: HashMap, 19 | } 20 | 21 | /// The symbol table for a module and all of its imported modules. 22 | #[derive(Debug, Default, Clone)] 23 | pub struct SymbolTable { 24 | // Maps modules to their respective symbol tables. 25 | map: HashMap>, 26 | } 27 | 28 | impl SymbolTable { 29 | pub fn insert(&mut self, url: Url, other: Arc) { 30 | self.map.insert(url, other); 31 | } 32 | } 33 | 34 | #[derive(Clone, Debug)] 35 | pub enum DeclMeta { 36 | Data { params: Telescope }, 37 | Codata { params: Telescope }, 38 | Def { params: Telescope }, 39 | Codef { params: Telescope }, 40 | Ctor { params: Telescope }, 41 | Dtor { params: Telescope }, 42 | Let { params: Telescope }, 43 | } 44 | -------------------------------------------------------------------------------- /lang/lsp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lsp-server" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | # lsp 16 | tower-lsp-server = { workspace = true } 17 | # asynchronous locks 18 | async-lock = "2" 19 | # fancy error messages 20 | miette = { workspace = true } 21 | # URLs 22 | url = { workspace = true } 23 | # workspace members 24 | ast = { path = "../ast" } 25 | driver = { path = "../driver" } 26 | printer = { path = "../printer" } 27 | miette_util = { path = "../miette_util" } 28 | -------------------------------------------------------------------------------- /lang/lsp/README.md: -------------------------------------------------------------------------------- 1 | # LSP Language Server 2 | 3 | Rust library providing a language server implementing the [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/) for the object language. 4 | -------------------------------------------------------------------------------- /lang/lsp/src/capabilities.rs: -------------------------------------------------------------------------------- 1 | use tower_lsp_server::lsp_types::*; 2 | 3 | pub fn capabilities() -> ServerCapabilities { 4 | let text_document_sync = { 5 | let options = TextDocumentSyncOptions { 6 | open_close: Some(true), 7 | change: Some(TextDocumentSyncKind::FULL), 8 | ..Default::default() 9 | }; 10 | Some(TextDocumentSyncCapability::Options(options)) 11 | }; 12 | 13 | let hover_provider = Some(HoverProviderCapability::Simple(true)); 14 | 15 | let code_action_provider = Some(CodeActionProviderCapability::Simple(true)); 16 | 17 | let document_formatting_provider = Some(OneOf::Left(true)); 18 | 19 | let definition_provider = Some(OneOf::Left(true)); 20 | 21 | ServerCapabilities { 22 | text_document_sync, 23 | hover_provider, 24 | code_action_provider, 25 | document_formatting_provider, 26 | definition_provider, 27 | ..Default::default() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lang/lsp/src/conversion/mod.rs: -------------------------------------------------------------------------------- 1 | use miette::Severity; 2 | use tower_lsp_server::lsp_types::DiagnosticSeverity; 3 | 4 | mod uri_to_url; 5 | 6 | pub trait FromLsp { 7 | type Target; 8 | 9 | #[allow(clippy::wrong_self_convention)] 10 | fn from_lsp(self) -> Self::Target; 11 | } 12 | 13 | pub trait ToLsp { 14 | type Target; 15 | 16 | fn to_lsp(self) -> Self::Target; 17 | } 18 | 19 | impl ToLsp for miette::Severity { 20 | type Target = DiagnosticSeverity; 21 | 22 | fn to_lsp(self) -> DiagnosticSeverity { 23 | match self { 24 | Severity::Error => DiagnosticSeverity::ERROR, 25 | Severity::Warning => DiagnosticSeverity::WARNING, 26 | Severity::Advice => DiagnosticSeverity::HINT, 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lang/lsp/src/conversion/uri_to_url.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use tower_lsp_server::lsp_types::Uri; 4 | 5 | use super::{FromLsp, ToLsp}; 6 | 7 | impl FromLsp for &Uri { 8 | type Target = url::Url; 9 | 10 | fn from_lsp(self) -> Self::Target { 11 | url::Url::parse(self.as_str()).expect("Failed to parse URI") 12 | } 13 | } 14 | 15 | impl ToLsp for &url::Url { 16 | type Target = Uri; 17 | 18 | fn to_lsp(self) -> Self::Target { 19 | Uri::from_str(self.as_str()).expect("Failed to parse URL") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lang/lsp/src/format.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of the formatting functionality of the LSP server 2 | use tower_lsp_server::jsonrpc::Result; 3 | use tower_lsp_server::lsp_types::*; 4 | 5 | use printer::Print; 6 | 7 | use crate::conversion::FromLsp; 8 | 9 | use super::server::*; 10 | 11 | pub async fn formatting( 12 | server: &Server, 13 | params: DocumentFormattingParams, 14 | ) -> Result>> { 15 | let text_document = params.text_document; 16 | 17 | server 18 | .client 19 | .log_message( 20 | MessageType::INFO, 21 | format!("Formatting request: {}", text_document.uri.from_lsp()), 22 | ) 23 | .await; 24 | 25 | let mut db = server.database.write().await; 26 | 27 | let prg = match db.ust(&text_document.uri.from_lsp()).await { 28 | Ok(prg) => prg, 29 | Err(_) => return Ok(None), 30 | }; 31 | 32 | let rng: Range = Range { 33 | start: Position { line: 0, character: 0 }, 34 | end: Position { line: u32::MAX, character: u32::MAX }, 35 | }; 36 | 37 | let formatted_prog: String = prg.print_to_string(None); 38 | 39 | let text_edit: TextEdit = TextEdit { range: rng, new_text: formatted_prog }; 40 | 41 | Ok(Some(vec![text_edit])) 42 | } 43 | -------------------------------------------------------------------------------- /lang/lsp/src/gotodefinition.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of the goto-definition functionality of the LSP server 2 | 3 | use tower_lsp_server::{jsonrpc, lsp_types::*}; 4 | 5 | use super::conversion::*; 6 | use super::server::*; 7 | 8 | pub async fn goto_definition( 9 | server: &Server, 10 | params: GotoDefinitionParams, 11 | ) -> jsonrpc::Result> { 12 | let pos_params = params.text_document_position_params; 13 | let text_document = pos_params.text_document; 14 | 15 | server 16 | .client 17 | .log_message( 18 | MessageType::INFO, 19 | format!("GotoDefinition request: {}", text_document.uri.from_lsp()), 20 | ) 21 | .await; 22 | 23 | let pos = pos_params.position; 24 | let mut db = server.database.write().await; 25 | let info = db.location_to_index(&text_document.uri.from_lsp(), pos); 26 | let info = match info { 27 | Some(idx) => db.goto_at_index(&text_document.uri.from_lsp(), idx).await, 28 | None => None, 29 | }; 30 | let res = info.and_then(|info| { 31 | let range = db.span_to_locations(&info.0, info.1); 32 | match range { 33 | Some(range) => { 34 | Some(GotoDefinitionResponse::Scalar(Location { uri: info.0.to_lsp(), range })) 35 | } 36 | None => None, 37 | } 38 | }); 39 | Ok(res) 40 | } 41 | -------------------------------------------------------------------------------- /lang/lsp/src/hover.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of the type-on-hover functionality of the LSP server 2 | use driver::*; 3 | use miette_util::codespan::Span; 4 | use tower_lsp_server::{jsonrpc, lsp_types::*}; 5 | 6 | use super::conversion::*; 7 | use super::server::*; 8 | 9 | // The implementation of the hover functionality that gets called by the LSP server. 10 | pub async fn hover(server: &Server, params: HoverParams) -> jsonrpc::Result> { 11 | let pos_params = params.text_document_position_params; 12 | let text_document = pos_params.text_document; 13 | 14 | server 15 | .client 16 | .log_message(MessageType::INFO, format!("Hover request: {}", text_document.uri.from_lsp())) 17 | .await; 18 | 19 | let pos = pos_params.position; 20 | let mut db = server.database.write().await; 21 | let info = db.location_to_index(&text_document.uri.from_lsp(), pos); 22 | 23 | let info = match info { 24 | Some(idx) => db.hoverinfo_at_index(&text_document.uri.from_lsp(), idx).await, 25 | None => None, 26 | }; 27 | 28 | let res = info.map(|info| info_to_hover(&db, &text_document.uri, info)); 29 | Ok(res) 30 | } 31 | 32 | fn info_to_hover(db: &Database, uri: &Uri, contents: (Span, HoverContents)) -> Hover { 33 | let range = db.span_to_locations(&uri.from_lsp(), contents.0); 34 | Hover { contents: contents.1, range } 35 | } 36 | -------------------------------------------------------------------------------- /lang/lsp/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod capabilities; 2 | mod codeactions; 3 | mod conversion; 4 | mod diagnostics; 5 | mod format; 6 | mod gotodefinition; 7 | mod hover; 8 | mod server; 9 | 10 | pub use server::*; 11 | -------------------------------------------------------------------------------- /lang/miette_util/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "miette_util" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | miette = { workspace = true } 16 | -------------------------------------------------------------------------------- /lang/parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parser" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | # lexer generator 16 | logos = "0.14.0" 17 | # Deriving 18 | derivative = { workspace = true } 19 | # parser generator 20 | lalrpop = "0.20" 21 | lalrpop-util = "0.20" 22 | # url (for file locations) 23 | url = "2.5.0" 24 | miette = { workspace = true } 25 | thiserror = { workspace = true } 26 | num-bigint = { workspace = true } 27 | miette_util = { path = "../miette_util" } 28 | 29 | [build-dependencies.lalrpop] 30 | version = "0.19" 31 | features = ["lexer"] 32 | -------------------------------------------------------------------------------- /lang/parser/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | lalrpop::process_root().unwrap(); 3 | } 4 | -------------------------------------------------------------------------------- /lang/parser/src/cst/ident.rs: -------------------------------------------------------------------------------- 1 | use derivative::Derivative; 2 | use miette_util::codespan::Span; 3 | 4 | #[derive(Debug, Clone, Derivative)] 5 | #[derivative(Eq, PartialEq, Hash)] 6 | pub struct Ident { 7 | #[derivative(PartialEq = "ignore", Hash = "ignore")] 8 | pub span: Span, 9 | pub id: String, 10 | } 11 | 12 | #[derive(Debug, Clone, Derivative)] 13 | #[derivative(Eq, PartialEq, Hash)] 14 | pub struct Operator { 15 | #[derivative(PartialEq = "ignore", Hash = "ignore")] 16 | pub span: Span, 17 | pub id: String, 18 | } 19 | -------------------------------------------------------------------------------- /lang/parser/src/cst/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Concrete syntax tree (CST) 2 | //! 3 | //! This representation is used as the output of the parser and as the input of the lowering stage that follows 4 | //! in the compiler pipeline. The structure of the CST therefore corresponds closely to the grammar of the surface 5 | //! syntax as implemented by the parser. 6 | 7 | pub mod decls; 8 | pub mod exp; 9 | pub mod ident; 10 | 11 | pub use ident::Ident; 12 | -------------------------------------------------------------------------------- /lang/parser/src/grammar/mod.rs: -------------------------------------------------------------------------------- 1 | use lalrpop_util::lalrpop_mod; 2 | 3 | mod util; 4 | 5 | lalrpop_mod!( 6 | #[allow(clippy::all)] 7 | #[allow(unused_imports)] 8 | #[allow(dead_code)] 9 | pub cst, "/grammar/cst.rs" 10 | ); 11 | -------------------------------------------------------------------------------- /lang/parser/src/grammar/util.rs: -------------------------------------------------------------------------------- 1 | use miette_util::codespan::{ByteIndex, Span}; 2 | 3 | pub fn span(l: usize, r: usize) -> Span { 4 | Span { start: ByteIndex(l as u32), end: ByteIndex(r as u32) } 5 | } 6 | -------------------------------------------------------------------------------- /lang/parser/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod cst; 2 | mod grammar; 3 | pub mod lexer; 4 | mod result; 5 | 6 | use lexer::Lexer; 7 | use url::Url; 8 | 9 | use grammar::cst::{ExpParser, ModuleContentsParser}; 10 | pub use result::*; 11 | 12 | pub fn parse_exp(s: &str) -> Result, ParseError> { 13 | let lexer = Lexer::new(s); 14 | let parser = ExpParser::new(); 15 | parser.parse(lexer).map_err(From::from) 16 | } 17 | 18 | pub fn parse_module(uri: Url, s: &str) -> Result { 19 | let lexer = Lexer::new(s); 20 | let parser = ModuleContentsParser::new(); 21 | let (use_decls, decls) = parser.parse(lexer)?; 22 | Ok(cst::decls::Module { uri, use_decls, decls }) 23 | } 24 | -------------------------------------------------------------------------------- /lang/printer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "printer" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | pretty = { workspace = true } 16 | askama_escape = "0.10.3" 17 | # url (for file locations) 18 | url = "2.5.0" -------------------------------------------------------------------------------- /lang/printer/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use pretty::DocAllocator; 2 | pub use pretty::termcolor; 3 | pub use pretty::termcolor::Color; 4 | pub use pretty::termcolor::ColorChoice; 5 | pub use pretty::termcolor::ColorSpec; 6 | pub use pretty::termcolor::StandardStream; 7 | pub use pretty::termcolor::WriteColor; 8 | 9 | mod render; 10 | pub mod theme; 11 | pub mod tokens; 12 | pub mod types; 13 | pub mod util; 14 | 15 | pub use types::*; 16 | 17 | pub const DEFAULT_WIDTH: usize = 100; 18 | -------------------------------------------------------------------------------- /lang/printer/src/render/mod.rs: -------------------------------------------------------------------------------- 1 | mod latex; 2 | mod termcolor; 3 | 4 | pub use latex::*; 5 | pub use termcolor::*; 6 | -------------------------------------------------------------------------------- /lang/printer/src/theme.rs: -------------------------------------------------------------------------------- 1 | use pretty::DocAllocator; 2 | 3 | use super::types::*; 4 | 5 | pub trait ThemeExt<'a> { 6 | fn keyword(&'a self, text: &str) -> Builder<'a>; 7 | fn ctor(&'a self, text: &str) -> Builder<'a>; 8 | fn dtor(&'a self, text: &str) -> Builder<'a>; 9 | fn typ(&'a self, text: &str) -> Builder<'a>; 10 | fn comment(&'a self, text: &str) -> Builder<'a>; 11 | } 12 | 13 | impl<'a> ThemeExt<'a> for Alloc<'a> { 14 | fn keyword(&'a self, text: &str) -> Builder<'a> { 15 | self.text(text.to_owned()).annotate(Anno::Keyword) 16 | } 17 | 18 | fn ctor(&'a self, text: &str) -> Builder<'a> { 19 | self.text(text.to_owned()).annotate(Anno::Ctor) 20 | } 21 | 22 | fn dtor(&'a self, text: &str) -> Builder<'a> { 23 | self.text(text.to_owned()).annotate(Anno::Dtor) 24 | } 25 | 26 | fn typ(&'a self, text: &str) -> Builder<'a> { 27 | self.text(text.to_owned()).annotate(Anno::Type) 28 | } 29 | 30 | fn comment(&'a self, text: &str) -> Builder<'a> { 31 | self.text(text.to_owned()).annotate(Anno::Comment) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lang/transformations/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "transformations" 3 | 4 | # Inherited from workspace Cargo.toml 5 | version.workspace = true 6 | edition.workspace = true 7 | rust-version.workspace = true 8 | authors.workspace = true 9 | license.workspace = true 10 | homepage.workspace = true 11 | repository.workspace = true 12 | categories.workspace = true 13 | 14 | [dependencies] 15 | url = "2" 16 | # error handling 17 | miette = { workspace = true } 18 | thiserror = { workspace = true } 19 | derivative = { workspace = true } 20 | # workspace members 21 | ast = { path = "../ast" } 22 | miette_util = { path = "../miette_util" } 23 | -------------------------------------------------------------------------------- /lang/transformations/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod lifting; 2 | pub mod xfunc; 3 | 4 | pub use lifting::*; 5 | pub use xfunc::*; 6 | -------------------------------------------------------------------------------- /lang/transformations/src/xfunc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod matrix; 2 | pub mod result; 3 | 4 | pub fn as_matrix(prg: &ast::Module) -> Result { 5 | matrix::build(prg) 6 | } 7 | 8 | pub fn repr(prg: &matrix::Prg, name: &str) -> Result { 9 | prg.map 10 | .get(name) 11 | .ok_or_else(|| crate::result::XfuncError::Impossible { 12 | message: format!("Could not resolve {name}"), 13 | span: None, 14 | }) 15 | .map(|x| x.repr) 16 | } 17 | 18 | pub fn as_data( 19 | prg: &matrix::Prg, 20 | name: &str, 21 | ) -> Result<(ast::Data, Vec), crate::result::XfuncError> { 22 | prg.map 23 | .get(name) 24 | .ok_or_else(|| crate::result::XfuncError::Impossible { 25 | message: format!("Could not resolve {name}"), 26 | span: None, 27 | }) 28 | .map(|x| x.as_data(&prg.uri)) 29 | } 30 | 31 | pub fn as_codata( 32 | prg: &matrix::Prg, 33 | name: &str, 34 | ) -> Result<(ast::Codata, Vec), crate::result::XfuncError> { 35 | prg.map 36 | .get(name) 37 | .ok_or_else(|| crate::result::XfuncError::Impossible { 38 | message: format!("Could not resolve {name}"), 39 | span: None, 40 | }) 41 | .map(|x| x.as_codata(&prg.uri)) 42 | } 43 | -------------------------------------------------------------------------------- /lang/transformations/src/xfunc/result.rs: -------------------------------------------------------------------------------- 1 | use miette::{Diagnostic, SourceSpan}; 2 | use thiserror::Error; 3 | 4 | #[derive(Error, Diagnostic, Debug, Clone)] 5 | pub enum XfuncError { 6 | #[error("An unexpected internal error occurred: {message}")] 7 | #[diagnostic(code("E-XXX"))] 8 | /// This error should not occur. 9 | /// Some internal invariant has been violated. 10 | Impossible { 11 | message: String, 12 | #[label] 13 | span: Option, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | use_small_heuristics = "Max" 2 | -------------------------------------------------------------------------------- /scripts/check_examples_index.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Get the list of .pol files in the examples directory 5 | pol_files=$(find examples -maxdepth 1 -name "*.pol" -printf "%f\n" | sort) 6 | 7 | # Extract the 'path' entries from index.json 8 | index_paths=$(jq -r '.[].path' examples/index.json | sort) 9 | 10 | # Compare the two lists 11 | if diff <(echo "$pol_files") <(echo "$index_paths") >/dev/null; then 12 | echo "Success: examples/index.json and examples/*.pol files are in sync." 13 | else 14 | echo "Error: examples/index.json and examples/*.pol are not in sync." 15 | echo "Diff:" 16 | diff <(echo "$pol_files") <(echo "$index_paths") 17 | fi 18 | -------------------------------------------------------------------------------- /scripts/git-hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Pre-commit hook 3 | # Place into `.git/hooks` or use `git config core.hooksPath scripts/git-hooks` 4 | # from the root of the repository 5 | 6 | set -e 7 | 8 | cargo test --all 9 | cargo clippy --all -- -Dwarnings 10 | cargo fmt --all --check 11 | ./scripts/check_examples_index.sh 12 | (cd web; make lint) 13 | -------------------------------------------------------------------------------- /std/README.md: -------------------------------------------------------------------------------- 1 | # Standard Library 2 | 3 | The Polarity Standard Library. 4 | 5 | ## Overview 6 | 7 | ```text 8 | ├── std The Polarity Standard Library 9 | │ ├── codata A collection of commonly used codata types 10 | │ └── data A collection of commonly used data types 11 | ``` 12 | 13 | ## Conventions 14 | 15 | We follow the following naming conventions in the standard library: 16 | 17 | * Polarity filenames and folder names are in `snake_case`. Example: `data/option.pol`. 18 | * `data` and `codata` declaration names are in `CamelCase`. Example: `data Option`. 19 | * Destructors and top-level let bindings are in `snake_case`. Example: `Fun.ap`. 20 | * Constructors are in `CamelCase`. Example: `Some`. 21 | 22 | Where syntax and naming decisions are arbitrary, we loosely follow the Rust conventions. 23 | 24 | All declarations use ASCII characters only. This is to ensure that there is always a unique natural language term to refer to any given declaration. It also ensures the standard library can easily be searched and indexed. 25 | There may be non-ASCII Unicode characters in shorthand notation, comments and documentation strings. 26 | -------------------------------------------------------------------------------- /std/codata/fun.pol: -------------------------------------------------------------------------------- 1 | /// The type of non-dependent functions. 2 | codata Fun(a b: Type) { 3 | /// Application of a function to its argument. 4 | Fun(a, b).ap(implicit a b: Type, x: a): b, 5 | } 6 | 7 | infix _ -> _ := Fun(_,_) 8 | 9 | /// The polymorphic identity function. 10 | codef Id(a: Type): Fun(a, a) { .ap(_, _, x) => x } 11 | -------------------------------------------------------------------------------- /std/codata/pair.pol: -------------------------------------------------------------------------------- 1 | /// The codata type of pairs defined by a first and second projection. 2 | codata Pair(a b: Type) { 3 | /// First projection on a pair. 4 | Pair(a, b).fst(implicit a b: Type): a, 5 | /// Second projection on a pair. 6 | Pair(a, b).snd(implicit a b: Type): b, 7 | } 8 | 9 | /// Constructing an element of the pair type. 10 | codef MkPair(a b: Type, x: a, y: b): Pair(a, b) { 11 | .fst(_, _) => x, 12 | .snd(_, _) => y, 13 | } 14 | -------------------------------------------------------------------------------- /std/codata/pi.pol: -------------------------------------------------------------------------------- 1 | use "./fun.pol" 2 | 3 | /// The dependent function type. 4 | codata Pi(a: Type, p: a -> Type) { 5 | Pi(a, p).dap(a: Type, p: a -> Type, x: a): p.ap(x), 6 | } 7 | -------------------------------------------------------------------------------- /std/codata/sigma.pol: -------------------------------------------------------------------------------- 1 | use "./fun.pol" 2 | 3 | /// The (strong) Sigma type defined by first and second projections. 4 | codata Sigma(A: Type, T: A -> Type) { 5 | Sigma(A,T).proj1(A: Type, T: A -> Type): A, 6 | (self: Sigma(A,T)).proj2(A: Type, T: A -> Type): T.ap(self.proj1(A,T)), 7 | } 8 | -------------------------------------------------------------------------------- /std/codata/stream.pol: -------------------------------------------------------------------------------- 1 | /// The codata type of infinite streams. 2 | codata Stream(a: Type) { 3 | /// The head observation which yields the first element. 4 | Stream(a).hd(implicit a: Type): a, 5 | /// The tail observation which yields the remainder of the stream. 6 | Stream(a).tl(implicit a: Type): Stream(a), 7 | } 8 | 9 | /// An infinite stream which repeats the argument. 10 | codef Repeat(a: Type, elem: a): Stream(a) { 11 | .hd(_) => elem, 12 | .tl(_) => Repeat(a, elem), 13 | } 14 | -------------------------------------------------------------------------------- /std/codata/unit.pol: -------------------------------------------------------------------------------- 1 | /// The unit codata type. 2 | codata Unit { } 3 | -------------------------------------------------------------------------------- /std/data/bool.pol: -------------------------------------------------------------------------------- 1 | /// The type of boolean values. 2 | data Bool { 3 | /// The boolean constant True. 4 | T, 5 | /// The boolean constant False. 6 | F, 7 | } 8 | 9 | /// Negation of a boolean value. 10 | def Bool.neg: Bool { 11 | T => F, 12 | F => T, 13 | } 14 | 15 | /// Conjunction of two boolean values. 16 | def Bool.and(other: Bool): Bool { 17 | T => other, 18 | F => F, 19 | } 20 | 21 | /// Inclusive disjunction of two boolean values. 22 | def Bool.or(other: Bool): Bool { 23 | T => T, 24 | F => other, 25 | } 26 | 27 | /// Exclusive disjunction of two boolean values. 28 | def Bool.xor(other: Bool): Bool { 29 | T => 30 | other.match { 31 | T => F, 32 | F => T, 33 | }, 34 | F => other, 35 | } 36 | 37 | /// Boolean nor function, also called joint denial or Peirce's function. 38 | def Bool.nor(other: Bool): Bool { 39 | T => F, 40 | F => 41 | other.match { 42 | T => F, 43 | F => T, 44 | }, 45 | } 46 | 47 | /// Boolean nand function, also called alternative denial or Sheffer stroke. 48 | def Bool.nand(other: Bool): Bool { 49 | T => 50 | other.match { 51 | T => F, 52 | F => T, 53 | }, 54 | F => T, 55 | } 56 | 57 | /// If-then-else combinator which returns the `then` argument if the boolean is true 58 | /// and the `else` argument otherwise. 59 | def Bool.ite(implicit a: Type, then else: a): a { 60 | T => then, 61 | F => else, 62 | } 63 | -------------------------------------------------------------------------------- /std/data/eq.pol: -------------------------------------------------------------------------------- 1 | /// The Martin-Löf equality type. 2 | data Eq(implicit a: Type, x y: a) { 3 | /// The reflexivity constructor. 4 | Refl(implicit a: Type, x: a): Eq(x, x), 5 | } 6 | 7 | /// Proof of symmetry of equality. 8 | def Eq(a:=a, x, y).sym(a: Type, x y: a): Eq(a:=a, y, x) { Refl(a, x) => Refl(a:=a, x) } 9 | 10 | /// Proof of transitivity of equality. 11 | def Eq(a:=a, x, y).trans(a: Type, x y z: a, h: Eq(a:=a, y, z)): Eq(a:=a, x, z) { Refl(a, x) => h } 12 | -------------------------------------------------------------------------------- /std/data/list.pol: -------------------------------------------------------------------------------- 1 | /// The type of finite lists. 2 | data List(a: Type) { 3 | /// The canonical empty list. 4 | Nil(a: Type): List(a), 5 | /// Appending one element to the front of a list. 6 | Cons(a: Type, x: a, xs: List(a)): List(a), 7 | } 8 | 9 | /// Concatenating two lists together. 10 | def List(a).concat(a: Type, other: List(a)): List(a) { 11 | Nil(_) => other, 12 | Cons(_, x, xs) => Cons(a, x, xs.concat(a, other)), 13 | } 14 | 15 | /// Appending an element to the end of a list. 16 | def List(a).snoc(a: Type, elem: a): List(a) { 17 | Nil(_) => Cons(a, elem, Nil(a)), 18 | Cons(_, x, xs) => Cons(a, x, xs.snoc(a, elem)), 19 | } 20 | 21 | /// Reversing the elements of a list. 22 | def List(a).reverse(a: Type): List(a) { 23 | Nil(_) => Nil(a), 24 | Cons(_, x, xs) => xs.reverse(a).snoc(a, x), 25 | } 26 | -------------------------------------------------------------------------------- /std/data/option.pol: -------------------------------------------------------------------------------- 1 | /// An optional value. 2 | data Option(a: Type) { 3 | /// No value 4 | None(a: Type): Option(a), 5 | /// Some value of type `a` 6 | Some(a: Type, x: a): Option(a), 7 | } 8 | -------------------------------------------------------------------------------- /std/data/ordering.pol: -------------------------------------------------------------------------------- 1 | use "./bool.pol" 2 | 3 | /// The result of comparing two totally-ordered values. 4 | data Ordering { 5 | /// Lesser than 6 | LT, 7 | /// Equal 8 | EQ, 9 | /// Greater than 10 | GT, 11 | } 12 | 13 | /// Returns `T` if the ordering is `EQ` 14 | def Ordering.isEq: Bool { 15 | LT => F, 16 | EQ => T, 17 | GT => F, 18 | } 19 | 20 | /// Returns `T` if the ordering is not `EQ` 21 | def Ordering.isNe: Bool { 22 | LT => T, 23 | EQ => F, 24 | GT => T, 25 | } 26 | 27 | /// Returns `T` if the ordering is `LT` 28 | def Ordering.isLt: Bool { 29 | LT => T, 30 | EQ => F, 31 | GT => F, 32 | } 33 | 34 | /// Returns `T` if the ordering is `GT` 35 | def Ordering.isGt: Bool { 36 | LT => F, 37 | EQ => F, 38 | GT => T, 39 | } 40 | 41 | /// Returns `T` if the ordering is `LT` or `EQ` 42 | def Ordering.isLe: Bool { 43 | LT => T, 44 | EQ => T, 45 | GT => F, 46 | } 47 | 48 | /// Returns `T` if the ordering is `EQ` or `GT` 49 | def Ordering.isGe: Bool { 50 | LT => F, 51 | EQ => T, 52 | GT => T, 53 | } 54 | -------------------------------------------------------------------------------- /std/data/pair.pol: -------------------------------------------------------------------------------- 1 | /// The data type of pairs defined by a constructor. 2 | data Pair(a b: Type) { 3 | /// Constructing an element of the pair type. 4 | MkPair(a b: Type, x: a, y: b): Pair(a, b), 5 | } 6 | 7 | /// Projection on the first element of a pair. 8 | def Pair(a, b).fst(a b: Type): a { MkPair(_, _, x, _) => x } 9 | 10 | /// Projection on the second element of a pair. 11 | def Pair(a, b).snd(a b: Type): b { MkPair(_, _, _, y) => y } 12 | -------------------------------------------------------------------------------- /std/data/result.pol: -------------------------------------------------------------------------------- 1 | /// The type for handling and propagating errors which contains the variants `Ok` and `Err`. 2 | data Result(a b: Type) { 3 | /// A successful result. 4 | Ok(a b: Type, res: a): Result(a, b), 5 | /// An error containing an error value. 6 | Err(a b: Type, err: b): Result(a, b), 7 | } 8 | -------------------------------------------------------------------------------- /std/data/sigma.pol: -------------------------------------------------------------------------------- 1 | use "../codata/fun.pol" 2 | 3 | /// The Sigma type defined by a tupling constructor. 4 | data Sigma(A: Type, T: A -> Type) { 5 | MkSigma(A: Type, T: A -> Type, x: A, w: T.ap(x)): Sigma(A,T), 6 | } 7 | -------------------------------------------------------------------------------- /std/data/unit.pol: -------------------------------------------------------------------------------- 1 | /// The unit data type. 2 | data Unit { MkUnit } 3 | -------------------------------------------------------------------------------- /std/data/vec.pol: -------------------------------------------------------------------------------- 1 | use "./nat.pol" 2 | 3 | /// The type of length-indexed lists. 4 | data Vec(n : Nat, a: Type) { 5 | /// The empty vector. 6 | VNil(a : Type) : Vec(Z, a), 7 | /// Appending one element to a vector. 8 | VCons(n : Nat, a: Type, x: a, xs: Vec(n,a)) : Vec(S(n), a), 9 | } 10 | 11 | /// The first element of a non-empty vector. 12 | def Vec(S(n), a).head(n: Nat, a: Type) : a { 13 | VNil(_) absurd, 14 | VCons(_,_,x,_) => x, 15 | } 16 | -------------------------------------------------------------------------------- /std/data/void.pol: -------------------------------------------------------------------------------- 1 | /// The trivially uninhabitated data type. 2 | data Void { } 3 | 4 | def Void.ex_falso(a: Type): a { } 5 | -------------------------------------------------------------------------------- /test/suites/fail-check/001.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: a 5 | │ 2: b 6 | │ 7 | ╭─[001.pol:6:21] 8 | 5 │ codef ConvertAny(a: Type, b: Type): Fun(a, b) { 9 | 6 │ .ap(a, b, x) => x 10 | · ┬ 11 | · ╰── While elaborating 12 | 7 │ } 13 | ╰──── 14 | -------------------------------------------------------------------------------- /test/suites/fail-check/001.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a: Type, b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | codef ConvertAny(a: Type, b: Type): Fun(a, b) { 6 | .ap(a, b, x) => x 7 | } 8 | -------------------------------------------------------------------------------- /test/suites/fail-check/002.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: Foo(False) 5 | │ 2: Foo(True) 6 | │ 7 | ╭─[002.pol:10:11] 8 | 9 │ Bar : Foo(True), 9 | 10 │ Baz : Foo(False), 10 | · ─────┬──── 11 | · ╰── Source of (1) 12 | 11 │ } 13 | 12 │ 14 | 13 │ def Foo(True).foo() : Nat { 15 | · ────┬──── 16 | · ╰── Source of (2) 17 | 14 │ Bar() => Z, 18 | 15 │ Baz() absurd, 19 | 16 │ } 20 | 17 │ 21 | 18 │ data Unit { Top } 22 | 19 │ 23 | 20 │ def Unit.example : Nat { 24 | 21 │ Top => Baz.foo 25 | · ─┬─ 26 | · ╰── While elaborating 27 | 22 │ } 28 | ╰──── 29 | help: The two subterms False and True are not equal. 30 | -------------------------------------------------------------------------------- /test/suites/fail-check/002.pol: -------------------------------------------------------------------------------- 1 | data Bool { True: Bool, False: Bool } 2 | 3 | data Nat { 4 | Z: Nat, 5 | S(n: Nat) : Nat, 6 | } 7 | 8 | data Foo(b: Bool) { 9 | Bar : Foo(True), 10 | Baz : Foo(False), 11 | } 12 | 13 | def Foo(True).foo() : Nat { 14 | Bar() => Z, 15 | Baz() absurd, 16 | } 17 | 18 | data Unit { Top } 19 | 20 | def Unit.example : Nat { 21 | Top => Baz.foo 22 | } 23 | -------------------------------------------------------------------------------- /test/suites/fail-check/003.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: Foo(False) 5 | │ 2: Foo(True) 6 | │ 7 | ╭─[003.pol:13:11] 8 | 12 │ Bar : Foo(True), 9 | 13 │ Baz : Foo(False), 10 | · ─────┬──── 11 | · ╰── Source of (1) 12 | 14 │ } 13 | 15 │ 14 | 16 │ def Foo(True).foo() : Nat { 15 | · ────┬──── 16 | · ╰── Source of (2) 17 | 17 │ Bar() => Z, 18 | 18 │ Baz() absurd, 19 | 19 │ } 20 | 20 │ 21 | 21 │ data Unit { Top } 22 | 22 │ 23 | 23 │ def Unit.example : Nat { 24 | 24 │ Top => Baz.foo 25 | · ─┬─ 26 | · ╰── While elaborating 27 | 25 │ } 28 | ╰──── 29 | help: The two subterms False and True are not equal. 30 | -------------------------------------------------------------------------------- /test/suites/fail-check/003.pol: -------------------------------------------------------------------------------- 1 | codata Bool {} 2 | 3 | codef True(): Bool {} 4 | codef False(): Bool {} 5 | 6 | data Nat { 7 | Z: Nat, 8 | S(n: Nat) : Nat, 9 | } 10 | 11 | data Foo(b: Bool) { 12 | Bar : Foo(True), 13 | Baz : Foo(False), 14 | } 15 | 16 | def Foo(True).foo() : Nat { 17 | Bar() => Z, 18 | Baz() absurd, 19 | } 20 | 21 | data Unit { Top } 22 | 23 | def Unit.example : Nat { 24 | Top => Baz.foo 25 | } 26 | -------------------------------------------------------------------------------- /test/suites/fail-check/004.expected: -------------------------------------------------------------------------------- 1 | T-013 2 | 3 | × Local comatch not supported for type Bool because Bool contains destructors with self parameters 4 | ╭─[004.pol:13:12] 5 | 12 │ def Unit.example : Bool { 6 | 13 │ ╭─▶ Top => comatch { 7 | 14 │ │ .neg_inverse => ?, 8 | 15 │ │ .and(other) => ?, 9 | 16 │ │ .not => ? 10 | 17 │ ╰─▶ } 11 | 18 │ } 12 | ╰──── 13 | help: Use a top-level codefinition instead 14 | -------------------------------------------------------------------------------- /test/suites/fail-check/004.pol: -------------------------------------------------------------------------------- 1 | data Eq (a: Type, x y: a) { 2 | Refl(a: Type, x: a) : Eq(a, x, x) 3 | } 4 | 5 | codata Bool { 6 | (x: Bool).neg_inverse: Eq(Bool, x, x.not.not), 7 | .and(other: Bool): Bool, 8 | .not: Bool 9 | } 10 | data Unit { Top } 11 | 12 | def Unit.example : Bool { 13 | Top => comatch { 14 | .neg_inverse => ?, 15 | .and(other) => ?, 16 | .not => ? 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /test/suites/fail-check/005.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: Eq(Nat, S(S(Z)), S(S(Z))) 5 | │ 2: Eq(Nat, S(S(Z)), opaqueTwo) 6 | │ 7 | ╭─[005.pol:4:26] 8 | 3 │ data Eq(a: Type, x y: a) { 9 | 4 │ Refl(a: Type, x: a): Eq(a, x, x) 10 | · ─────┬───── 11 | · ╰── Source of (1) 12 | 5 │ } 13 | ╰──── 14 | ╭─[005.pol:11:9] 15 | 10 │ /// This proof typechecks 16 | 11 │ let p2: Eq(Nat, S(S(Z)), opaqueTwo) {Refl(Nat, S(S(Z)))} 17 | · ─────────────┬───────────── ─────────┬──────── 18 | · │ ╰── While elaborating 19 | · ╰── Source of (2) 20 | ╰──── 21 | help: The two subterms S(S(Z)) and opaqueTwo are not equal. 22 | -------------------------------------------------------------------------------- /test/suites/fail-check/005.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | data Eq(a: Type, x y: a) { 4 | Refl(a: Type, x: a): Eq(a, x, x) 5 | } 6 | 7 | #[opaque] 8 | let opaqueTwo: Nat {S(S(Z))} 9 | 10 | /// This proof typechecks 11 | let p2: Eq(Nat, S(S(Z)), opaqueTwo) {Refl(Nat, S(S(Z)))} -------------------------------------------------------------------------------- /test/suites/fail-check/006.expected: -------------------------------------------------------------------------------- 1 | T-017 2 | 3 | × The metavariable 0 could not be solved 4 | ╭─[006.pol:3:20] 5 | 2 │ data List(implicit a: Type) { 6 | 3 │ Nil(a: Type) : List 7 | · ───── 8 | 4 │ } 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-check/006.pol: -------------------------------------------------------------------------------- 1 | // We cannot infer the implicit argument to List, which should be passed explicitly via `List(a:= a)`. 2 | data List(implicit a: Type) { 3 | Nil(a: Type) : List 4 | } 5 | -------------------------------------------------------------------------------- /test/suites/fail-check/007.expected: -------------------------------------------------------------------------------- 1 | T-017 2 | 3 | × The metavariable _0 could not be solved 4 | ╭─[007.pol:6:22] 5 | 5 │ 6 | 6 │ let example : Option(_) { None(_) } 7 | · ─ 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-check/007.pol: -------------------------------------------------------------------------------- 1 | data Option(a: Type) { 2 | None(a: Type) : Option(a), 3 | Some(a:Type, x: a) : Option(a) 4 | } 5 | 6 | let example : Option(_) { None(_) } 7 | -------------------------------------------------------------------------------- /test/suites/fail-check/008.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: B 5 | │ 2: A 6 | │ 7 | ╭─[008.pol:3:13] 8 | 2 │ data B {b} // annotate the type of b explicitly 9 | 3 │ data C (a : A) {} 10 | · ┬ 11 | · ╰── Source of (2) 12 | 4 │ 13 | 5 │ let f : C (b) {b} 14 | · ┬ 15 | · ╰── While elaborating 16 | ╰──── 17 | -------------------------------------------------------------------------------- /test/suites/fail-check/008.pol: -------------------------------------------------------------------------------- 1 | data A {a} 2 | data B {b} // annotate the type of b explicitly 3 | data C (a : A) {} 4 | 5 | let f : C (b) {b} 6 | -------------------------------------------------------------------------------- /test/suites/fail-check/009.expected: -------------------------------------------------------------------------------- 1 | T-016 2 | 3 | × Cannot automatically decide whether Type and Foo unify 4 | ╭─[009.pol:2:15] 5 | 1 │ data Foo { } 6 | 2 │ codata Bar(n: Foo) { } 7 | · ─── 8 | 3 │ codef Baz(n : Type, l1:Bar(n)) : Bar(n) { } 9 | · ──── ┬ 10 | · │ ╰── While elaborating 11 | ╰──── 12 | -------------------------------------------------------------------------------- /test/suites/fail-check/009.pol: -------------------------------------------------------------------------------- 1 | data Foo { } 2 | codata Bar(n: Foo) { } 3 | codef Baz(n : Type, l1:Bar(n)) : Bar(n) { } 4 | -------------------------------------------------------------------------------- /test/suites/fail-check/010.expected: -------------------------------------------------------------------------------- 1 | T-016 2 | 3 | × Cannot automatically decide whether T and ? unify 4 | ╭─[010.pol:4:14] 5 | 3 │ data Foo(a: Bool) { 6 | 4 │ Bar: Foo(T), 7 | · ─ 8 | 5 │ Baz: Foo(F) 9 | 6 │ } 10 | 7 │ 11 | 8 │ def Foo(?).foo: Foo(F) { 12 | · ─ 13 | 9 │ Bar => ?, 14 | · ────┬─── 15 | · ╰── While elaborating 16 | 10 │ Baz => ? 17 | ╰──── 18 | -------------------------------------------------------------------------------- /test/suites/fail-check/010.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | data Foo(a: Bool) { 4 | Bar: Foo(T), 5 | Baz: Foo(F) 6 | } 7 | 8 | def Foo(?).foo: Foo(F) { 9 | Bar => ?, 10 | Baz => ? 11 | } 12 | -------------------------------------------------------------------------------- /test/suites/fail-check/011-escaping-hole.expected: -------------------------------------------------------------------------------- 1 | T-022 2 | 3 | × The metavariable _0 was equated with an expression that contains b which is not in scope for _0 4 | ╭─[011-escaping-hole.pol:8:19] 5 | 7 │ #[transparent] 6 | 8 │ let foo(): Bool { _ } 7 | · ─ 8 | 9 │ 9 | 10 │ let bar(b: Bool): Eq(Bool, foo(), b) { 10 | 11 │ Refl(Bool, b) 11 | · ──────┬────── 12 | · ╰── While elaborating 13 | 12 │ } 14 | ╰──── 15 | help: This means that the metavariable cannot be solved automatically. 16 | -------------------------------------------------------------------------------- /test/suites/fail-check/011-escaping-hole.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | data Eq(a: Type, x y: a) { 4 | Refl(a: Type, x: a): Eq(a, x, x) 5 | } 6 | 7 | #[transparent] 8 | let foo(): Bool { _ } 9 | 10 | let bar(b: Bool): Eq(Bool, foo(), b) { 11 | Refl(Bool, b) 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/fail-check/012-nonlinear-args.expected: -------------------------------------------------------------------------------- 1 | T-020 2 | 3 | × The metavariable ?0 received b2 as an argument more than once 4 | ╭─[012-nonlinear-args.pol:9:46] 5 | 8 │ 6 | 9 │ def Eq(Bool, b1, b2).bar(b1 b2: Bool, x: Foo(?, b2)): Foo(b1, b2) { 7 | · ─ 8 | 10 │ Refl(_, _) => x 9 | · ┬ 10 | · ╰── While elaborating 11 | 11 │ } 12 | ╰──── 13 | help: This means that the metavariable cannot be solved automatically. 14 | -------------------------------------------------------------------------------- /test/suites/fail-check/012-nonlinear-args.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | data Eq(a: Type, x y: a) { 4 | Refl(a: Type, x: a): Eq(a, x, x) 5 | } 6 | 7 | data Foo(a b: Bool) {} 8 | 9 | def Eq(Bool, b1, b2).bar(b1 b2: Bool, x: Foo(?, b2)): Foo(b1, b2) { 10 | Refl(_, _) => x 11 | } 12 | -------------------------------------------------------------------------------- /test/suites/fail-check/013-eta-comatch.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: Eq(Test, comatch { .test(_) => T }, comatch { .test(_) => T }) 5 | │ 2: Eq(Test, comatch { .test(_) => T }, comatch { .test(_) => F }) 6 | │ 7 | ╭─[013-eta-comatch.pol:6:26] 8 | 5 │ data Eq(a: Type, x y: a) { 9 | 6 │ Refl(a: Type, x: a): Eq(a, x, x), 10 | · ─────┬───── 11 | · ╰── Source of (1) 12 | 7 │ } 13 | ╰──── 14 | ╭─[013-eta-comatch.pol:15:9] 15 | 14 │ 16 | 15 │ ╭─▶ let eq: Eq(Test, f.ap(Bool, Test, T), f.ap(Bool, Test, F)) {Refl(Test, 17 | · │ ─────────────────────────┬──────────────────────── 18 | · │ ╰── Source of (2) 19 | 16 │ ├─▶ f.ap(Bool, Test, T))} 20 | · ╰──── While elaborating 21 | ╰──── 22 | help: The two subterms T and F are not equal. 23 | -------------------------------------------------------------------------------- /test/suites/fail-check/013-eta-comatch.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a b: Type, x: a): b, 3 | } 4 | 5 | data Eq(a: Type, x y: a) { 6 | Refl(a: Type, x: a): Eq(a, x, x), 7 | } 8 | 9 | data Bool { T, F } 10 | 11 | codata Test { .test(x: Bool): Bool } 12 | 13 | codef f: Fun(Bool, Test) { .ap(Bool, Bool, x) => comatch { .test(_) => x } } 14 | 15 | let eq: Eq(Test, f.ap(Bool, Test, T), f.ap(Bool, Test, F)) {Refl(Test, 16 | f.ap(Bool, Test, T))} -------------------------------------------------------------------------------- /test/suites/fail-check/Regr-321.expected: -------------------------------------------------------------------------------- 1 | T-018 2 | 3 | × A case for constructor C was missing during evaluation. 4 | -------------------------------------------------------------------------------- /test/suites/fail-check/Regr-321.pol: -------------------------------------------------------------------------------- 1 | data Foo { 2 | A, 3 | B(y: C(A).type), 4 | C(x: B(A).type) 5 | } 6 | 7 | def Foo.type: Type { 8 | A => Foo, 9 | B(_) => Foo, 10 | } 11 | -------------------------------------------------------------------------------- /test/suites/fail-check/Regr-348.expected: -------------------------------------------------------------------------------- 1 | T-022 2 | 3 | × The metavariable ?1 was equated with an expression that contains f which is not in scope for ?1 4 | ╭─[Regr-348.pol:5:19] 5 | 4 │ 6 | 5 │ let bar(f: Fun(?, ?)): f.ap(?, ?, ?) { 7 | · ─ ┬ 8 | · │ ╰── While elaborating 9 | 6 │ ? 10 | ╰──── 11 | help: This means that the metavariable cannot be solved automatically. 12 | -------------------------------------------------------------------------------- /test/suites/fail-check/Regr-348.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a,b).ap(a b: Type, x: a) : b 3 | } 4 | 5 | let bar(f: Fun(?, ?)): f.ap(?, ?, ?) { 6 | ? 7 | } 8 | -------------------------------------------------------------------------------- /test/suites/fail-check/Regr-403.expected: -------------------------------------------------------------------------------- 1 | T-002 2 | 3 | × The following terms are not equal: 4 | │ 1: Eq(, \ap(_, _, x) => T, \ap(_, _, x) => T) 5 | │ 2: Eq(a:=Fun(Bool, Bool), \ap(_, _, x) => T, \ap(_, _, x) => F) 6 | │ 7 | ╭─[Regr-403.pol:6:29] 8 | 5 │ #[transparent] 9 | 6 │ let foo(y: Bool) : Fun(Bool, Bool) { 10 | · ────┬─── 11 | · ╰── Source of (1) 12 | 7 │ \ap(_,_,x) => y 13 | 8 │ } 14 | 9 │ 15 | 10 │ let proof: Eq(a := Fun(Bool, Bool), foo(T), foo(F)) { 16 | · ────────────────────┬─────────────────── 17 | · ╰── Source of (2) 18 | 11 │ Refl(a := Fun(Bool,Bool), foo(T)) 19 | · ────────────────┬──────────────── 20 | · ╰── While elaborating 21 | 12 │ } 22 | ╰──── 23 | help: The two subterms T and F are not equal. 24 | -------------------------------------------------------------------------------- /test/suites/fail-check/Regr-403.pol: -------------------------------------------------------------------------------- 1 | use "../../../std/data/eq.pol" 2 | use "../../../std/data/bool.pol" 3 | use "../../../std/codata/fun.pol" 4 | 5 | #[transparent] 6 | let foo(y: Bool) : Fun(Bool, Bool) { 7 | \ap(_,_,x) => y 8 | } 9 | 10 | let proof: Eq(a := Fun(Bool, Bool), foo(T), foo(F)) { 11 | Refl(a := Fun(Bool,Bool), foo(T)) 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/fail-check/suite.toml: -------------------------------------------------------------------------------- 1 | description = "Tests which fail during the typechecking phase" 2 | fail = "check" 3 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-001.expected: -------------------------------------------------------------------------------- 1 | L-001 2 | 3 | × Undefined identifier MkUnit 4 | ╭─[L-001.pol:2:5] 5 | 1 │ def Unit.bar() : Unit { 6 | 2 │ MkUnit => Foo 7 | · ────── 8 | 3 │ } 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-001.pol: -------------------------------------------------------------------------------- 1 | def Unit.bar() : Unit { 2 | MkUnit => Foo 3 | } 4 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-01.expected: -------------------------------------------------------------------------------- 1 | L-002 2 | 3 | × Duplicate definition of True 4 | ╭─[L-002-01.pol:1:19] 5 | 1 │ data Bool { True, True } 6 | · ───── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-01.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, True } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-02.expected: -------------------------------------------------------------------------------- 1 | L-002 2 | 3 | × Duplicate definition of T 4 | ╭─[L-002-02.pol:2:1] 5 | 1 │ data T {} 6 | 2 │ data T {} 7 | · ───────── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-02.pol: -------------------------------------------------------------------------------- 1 | data T {} 2 | data T {} -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-03.expected: -------------------------------------------------------------------------------- 1 | L-002 2 | 3 | × Duplicate definition of T 4 | ╭─[L-002-03.pol:2:1] 5 | 1 │ data T {} 6 | 2 │ codata T {} 7 | · ─────────── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-03.pol: -------------------------------------------------------------------------------- 1 | data T {} 2 | codata T {} -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-04.expected: -------------------------------------------------------------------------------- 1 | L-002 2 | 3 | × Duplicate definition of T 4 | ╭─[L-002-04.pol:1:10] 5 | 1 │ data T { T } 6 | · ── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-04.pol: -------------------------------------------------------------------------------- 1 | data T { T } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-05.expected: -------------------------------------------------------------------------------- 1 | L-002 2 | 3 | × Duplicate definition of f 4 | ╭─[L-002-05.pol:5:1] 5 | 4 │ 6 | 5 │ ╭─▶ def Bool.f : Bool { 7 | 6 │ │ True => ?, 8 | 7 │ │ False => ?, 9 | 8 │ ╰─▶ } 10 | ╰──── 11 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-002-05.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | codata T { .f : Bool } 4 | 5 | def Bool.f : Bool { 6 | True => ?, 7 | False => ?, 8 | } 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-003.expected: -------------------------------------------------------------------------------- 1 | L-003 2 | 3 | × d must be used as destructor 4 | ╭─[L-003.pol:7:15] 5 | 6 │ def Unit.foo : ? { 6 | 7 │ MkUnit => d 7 | · ─ 8 | 8 │ } 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-003.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | codata Foo { .d : Bool } 3 | 4 | data Unit { MkUnit } 5 | 6 | def Unit.foo : ? { 7 | MkUnit => d 8 | } 9 | 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-005.expected: -------------------------------------------------------------------------------- 1 | L-005 2 | 3 | × Arguments to type constructor List must be provided for Cons 4 | ╭─[L-005.pol:3:5] 5 | 2 │ Nil(a : Type) : List(a), 6 | 3 │ Cons(a : Type, x : a, xs : List(a)) 7 | · ─────────────────────────────────── 8 | 4 │ } 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-005.pol: -------------------------------------------------------------------------------- 1 | data List(a : Type) { 2 | Nil(a : Type) : List(a), 3 | Cons(a : Type, x : a, xs : List(a)) 4 | } 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-010.expected: -------------------------------------------------------------------------------- 1 | L-010 2 | 3 | × Literal cannot be desugared because S/Z are not in program 4 | ╭─[L-010.pol:3:17] 5 | 2 │ 6 | 3 │ let foo : Nat { 5 } 7 | · ─ 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-010.pol: -------------------------------------------------------------------------------- 1 | data Nat {} 2 | 3 | let foo : Nat { 5 } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-011-ctor.expected: -------------------------------------------------------------------------------- 1 | L-011 2 | 3 | × Mismatched named arguments: given x, expected head 4 | ╭─[L-011-ctor.pol:9:15] 5 | 8 │ let example1: List { 6 | 9 │ Cons(x := True, xs := Nil) 7 | · ──── 8 | 10 │ } 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-011-ctor.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | data List { 4 | Nil, 5 | Cons(head: Bool, tail: List) 6 | } 7 | 8 | let example1: List { 9 | Cons(x := True, xs := Nil) 10 | } 11 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-011-def.expected: -------------------------------------------------------------------------------- 1 | L-011 2 | 3 | × Mismatched named arguments: given other_wrong, expected other 4 | ╭─[L-011-def.pol:8:45] 5 | 7 │ 6 | 8 │ let example: Bool { True.and(other_wrong := False) } 7 | · ───── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-011-def.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | def Bool.and(other: Bool): Bool { 4 | True => other, 5 | False => False 6 | } 7 | 8 | let example: Bool { True.and(other_wrong := False) } 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-011-tyctor.expected: -------------------------------------------------------------------------------- 1 | L-011 2 | 3 | × Mismatched named arguments: given wrong, expected elem 4 | ╭─[L-011-tyctor.pol:8:31] 5 | 7 │ 6 | 8 │ let example2: Option(wrong := Bool) { None(Bool) } 7 | · ──── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-011-tyctor.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | data Option(elem: Type) { 4 | None(elem: Type): Option(elem), 5 | Some(elem: Type, x: elem): Option(elem), 6 | } 7 | 8 | let example2: Option(wrong := Bool) { None(Bool) } 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-012.expected: -------------------------------------------------------------------------------- 1 | L-012 2 | 3 | × Used named argument wrong for wildcard parameter 4 | ╭─[L-012.pol:3:13] 5 | 2 │ 6 | 3 │ data Option(_: Type) { 7 | · ─ 8 | 4 │ None(elem: Type): Option(elem), 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-012.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | data Option(_: Type) { 4 | None(elem: Type): Option(elem), 5 | Some(elem: Type, x: elem): Option(elem), 6 | } 7 | 8 | let example2: Option(wrong := Bool) { None(Bool) } 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-015.expected: -------------------------------------------------------------------------------- 1 | L-015 2 | 3 | × Type universe "Type" does not take arguments 4 | ╭─[L-015.pol:1:13] 5 | 1 │ let foo() : Type(?) { ? } 6 | · ─────── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-015.pol: -------------------------------------------------------------------------------- 1 | let foo() : Type(?) { ? } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016a.expected: -------------------------------------------------------------------------------- 1 | L-016 2 | 3 | × "Type" is not a valid identifier 4 | ╭─[L-016a.pol:1:1] 5 | 1 │ data Type {} 6 | · ──────────── 7 | ╰──── 8 | help: "Type" is the name of the impredicative type universe. 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016a.pol: -------------------------------------------------------------------------------- 1 | data Type {} -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016b.expected: -------------------------------------------------------------------------------- 1 | L-016 2 | 3 | × "Type" is not a valid identifier 4 | ╭─[L-016b.pol:1:1] 5 | 1 │ codata Type {} 6 | · ────────────── 7 | ╰──── 8 | help: "Type" is the name of the impredicative type universe. 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016b.pol: -------------------------------------------------------------------------------- 1 | codata Type {} -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016c.expected: -------------------------------------------------------------------------------- 1 | L-016 2 | 3 | × "Type" is not a valid identifier 4 | ╭─[L-016c.pol:1:12] 5 | 1 │ data Foo { Type : Foo } 6 | · ─────────── 7 | ╰──── 8 | help: "Type" is the name of the impredicative type universe. 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016c.pol: -------------------------------------------------------------------------------- 1 | data Foo { Type : Foo } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016d.expected: -------------------------------------------------------------------------------- 1 | L-016 2 | 3 | × "Type" is not a valid identifier 4 | ╭─[L-016d.pol:2:14] 5 | 1 │ data Bool { T, F } 6 | 2 │ codata Foo { .Type : Bool } 7 | · ──────────── 8 | ╰──── 9 | help: "Type" is the name of the impredicative type universe. 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016d.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | codata Foo { .Type : Bool } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016e.expected: -------------------------------------------------------------------------------- 1 | L-016 2 | 3 | × "Type" is not a valid identifier 4 | ╭─[L-016e.pol:2:1] 5 | 1 │ data Bool { T, F } 6 | 2 │ let Type : Bool { T } 7 | · ───────────────────── 8 | ╰──── 9 | help: "Type" is the name of the impredicative type universe. 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016e.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | let Type : Bool { T } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016f.expected: -------------------------------------------------------------------------------- 1 | L-016 2 | 3 | × "Type" is not a valid identifier 4 | ╭─[L-016f.pol:1:9] 5 | 1 │ let foo(Type: Type): Type { 6 | · ──── 7 | 2 │ Type 8 | ╰──── 9 | help: "Type" is the name of the impredicative type universe. 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-016f.pol: -------------------------------------------------------------------------------- 1 | let foo(Type: Type): Type { 2 | Type 3 | } -------------------------------------------------------------------------------- /test/suites/fail-lower/L-017.expected: -------------------------------------------------------------------------------- 1 | L-017 2 | 3 | × Unknown operator: +++ 4 | ╭─[L-017.pol:3:27] 5 | 2 │ 6 | 3 │ let f(x: Bool) : Bool { x +++ x} 7 | · ─── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-017.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | let f(x: Bool) : Bool { x +++ x} -------------------------------------------------------------------------------- /test/suites/fail-lower/L-018.expected: -------------------------------------------------------------------------------- 1 | L-018 2 | 3 | × Operator already defined: -> 4 | ╭─[L-018.pol:5:1] 5 | 4 │ 6 | 5 │ infix _ -> _ := Fun(_,_) 7 | · ──────────────────────── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-018.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { Fun(a,b).ap(a b: Type, x: a): b } 2 | 3 | infix _ -> _ := Fun(_,_) 4 | 5 | infix _ -> _ := Fun(_,_) -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019a.expected: -------------------------------------------------------------------------------- 1 | L-019 2 | 3 | × Invalid infix declaration: The left hand side of an infix declaration must have the form "_ + _". 4 | ╭─[L-019a.pol:1:7] 5 | 1 │ infix a -> b := Fun(_,_) 6 | · ────── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019a.pol: -------------------------------------------------------------------------------- 1 | infix a -> b := Fun(_,_) -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019b.expected: -------------------------------------------------------------------------------- 1 | L-019 2 | 3 | × Invalid infix declaration: The right hand side of an infix declaration must take exactly two arguments. 4 | ╭─[L-019b.pol:1:17] 5 | 1 │ infix _ -> _ := Fun(_,_,_) 6 | · ────────── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019b.pol: -------------------------------------------------------------------------------- 1 | infix _ -> _ := Fun(_,_,_) -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019c.expected: -------------------------------------------------------------------------------- 1 | L-019 2 | 3 | × Invalid infix declaration: The right hand side of an infix declaration must have the form "T(_,_)". 4 | ╭─[L-019c.pol:1:17] 5 | 1 │ infix _ -> _ := Fun(a,b) 6 | · ──────── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019c.pol: -------------------------------------------------------------------------------- 1 | infix _ -> _ := Fun(a,b) -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019d.expected: -------------------------------------------------------------------------------- 1 | L-001 2 | 3 | × Undefined identifier Fun 4 | ╭─[L-019d.pol:1:17] 5 | 1 │ infix _ -> _ := Fun(_,_) 6 | · ─── 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-019d.pol: -------------------------------------------------------------------------------- 1 | infix _ -> _ := Fun(_,_) -------------------------------------------------------------------------------- /test/suites/fail-lower/L-let-lower.expected: -------------------------------------------------------------------------------- 1 | L-XXX 2 | 3 | × An unexpected internal error occurred: Lowering of local let expressions not implemented yet 4 | ╭─[L-let-lower.pol:3:16] 5 | 2 │ 6 | 3 │ ╭─▶ let foo: Nat { let x := Z; 7 | 4 │ ╰─▶ S(x) } 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/L-let-lower.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(x : Nat)} 2 | 3 | let foo: Nat { let x := Z; 4 | S(x) } -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-318a.expected: -------------------------------------------------------------------------------- 1 | L-014 2 | 3 | × Too many arguments provided 4 | ╭─[Regr-318a.pol:4:16] 5 | 3 │ 6 | 4 │ let foo: T { K(True)} 7 | · ──── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-318a.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | data T { K } 3 | 4 | let foo: T { K(True)} -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-318b.expected: -------------------------------------------------------------------------------- 1 | L-014 2 | 3 | × Too many arguments provided 4 | ╭─[Regr-318b.pol:3:14] 5 | 2 │ 6 | 3 │ let foo: Foo(Type, Type) { ? } 7 | · ──── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-318b.pol: -------------------------------------------------------------------------------- 1 | data Foo(a: Type) {} 2 | 3 | let foo: Foo(Type, Type) { ? } 4 | -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-408.expected: -------------------------------------------------------------------------------- 1 | L-013 2 | 3 | × Missing argument for parameter a 4 | ╭─[Regr-408.pol:3:13] 5 | 2 │ 6 | 3 │ codef Ones: Stream { 7 | · ─────── 8 | 4 │ .head => S(Z), 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-408.pol: -------------------------------------------------------------------------------- 1 | codata Stream(a : Type) { Stream(a).head(a : Type): a, Stream(a).tail(a : Type): Stream(a) } 2 | 3 | codef Ones: Stream { 4 | .head => S(Z), 5 | .tail => Ones 6 | } 7 | -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-86.expected: -------------------------------------------------------------------------------- 1 | L-009 2 | 3 | × Expected a type constructor 4 | ╭─[Regr-86.pol:7:5] 5 | 6 │ 6 | 7 │ def MkUnit.test : Unit -> Unit { 7 | · ────── 8 | 8 │ MkUnit => ? 9 | ╰──── 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/Regr-86.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a b: Type, x: a): b 3 | } 4 | 5 | data Unit { MkUnit } 6 | 7 | def MkUnit.test : Unit -> Unit { 8 | MkUnit => ? 9 | } 10 | -------------------------------------------------------------------------------- /test/suites/fail-lower/suite.toml: -------------------------------------------------------------------------------- 1 | description = "Tests which fail during the lowering phase" 2 | fail = "lower" -------------------------------------------------------------------------------- /test/suites/fail-parse/P-001.expected: -------------------------------------------------------------------------------- 1 | P-005 2 | 3 | × InvalidToken 4 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-001.pol: -------------------------------------------------------------------------------- 1 | @ 2 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-002.expected: -------------------------------------------------------------------------------- 1 | P-002 2 | 3 | × Unexpected end of file. Expected "DocComment", "Identifier", "}" 4 | ╭─[P-002.pol:1:12] 5 | 1 │ data Bool { 6 | · ▲ 7 | ╰──── 8 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-002.pol: -------------------------------------------------------------------------------- 1 | data Bool { -------------------------------------------------------------------------------- /test/suites/fail-parse/P-003.expected: -------------------------------------------------------------------------------- 1 | P-002 2 | 3 | × Unexpected end of file. Expected "(", ")", ",", ".", ":", ":=", ";", "=>", "Identifier", "Operator", "_", "absurd", "as", "{", "}" 4 | ╭─[P-003.pol:1:9] 5 | 1 │ data foo 6 | ╰──── 7 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-003.pol: -------------------------------------------------------------------------------- 1 | data foo -------------------------------------------------------------------------------- /test/suites/fail-parse/P-004-let-1.expected: -------------------------------------------------------------------------------- 1 | P-003 2 | 3 | × Unexpected "Let", expected "(", "?", "Identifier", "NumLit", "\\", "_", "comatch" 4 | ╭─[P-004-let-1.pol:3:23] 5 | 2 │ 6 | 3 │ let x : Nat { let x : let ty := Nat; ty := Z; S(x) } 7 | · ─── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-004-let-1.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(x: Nat)} 2 | 3 | let x : Nat { let x : let ty := Nat; ty := Z; S(x) } 4 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-005-let-2.expected: -------------------------------------------------------------------------------- 1 | P-003 2 | 3 | × Unexpected "Let", expected "(", "?", "Identifier", "NumLit", "\\", "_", "comatch" 4 | ╭─[P-005-let-2.pol:3:30] 5 | 2 │ 6 | 3 │ let x : Nat { let x : Nat := let y := Z; y ; S(x) } 7 | · ─── 8 | ╰──── 9 | -------------------------------------------------------------------------------- /test/suites/fail-parse/P-005-let-2.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(x: Nat)} 2 | 3 | let x : Nat { let x : Nat := let y := Z; y ; S(x) } -------------------------------------------------------------------------------- /test/suites/fail-parse/suite.toml: -------------------------------------------------------------------------------- 1 | description = "Tests which fail during the lexing and parsing phase" 2 | fail = "parse" -------------------------------------------------------------------------------- /test/suites/success/001.ir.expected: -------------------------------------------------------------------------------- 1 | codef Id { .ap(x) => x } 2 | -------------------------------------------------------------------------------- /test/suites/success/001.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a: Type, b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | codef Id(a: Type): Fun(a, a) { 6 | .ap(a, b, x) => x 7 | } 8 | -------------------------------------------------------------------------------- /test/suites/success/002.ir.expected: -------------------------------------------------------------------------------- 1 | codef Compose(f, g) { .ap(x) => g.ap(f.ap(x)) } 2 | -------------------------------------------------------------------------------- /test/suites/success/002.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a: Type, b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | codef Compose(a: Type, b: Type, c: Type, f: Fun(a, b), g: Fun(b, c)) : Fun(a, c) { 6 | .ap(a', c', x) => g.ap(b, c, f.ap(a, b, x: a') : b) : c' 7 | } 8 | -------------------------------------------------------------------------------- /test/suites/success/003.ir.expected: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polarity-lang/polarity/763c7f2e47e1adff6f48680946aeacb65e9af923/test/suites/success/003.ir.expected -------------------------------------------------------------------------------- /test/suites/success/003.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | -------------------------------------------------------------------------------- /test/suites/success/004.ir.expected: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polarity-lang/polarity/763c7f2e47e1adff6f48680946aeacb65e9af923/test/suites/success/004.ir.expected -------------------------------------------------------------------------------- /test/suites/success/004.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | codata Stream { 4 | .head : Bool, 5 | .tail : Stream, 6 | } 7 | -------------------------------------------------------------------------------- /test/suites/success/005.ir.expected: -------------------------------------------------------------------------------- 1 | def .not { 2 | True => False, 3 | False => True, 4 | } 5 | 6 | def .false { Unit => True.not } 7 | -------------------------------------------------------------------------------- /test/suites/success/005.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | def Bool.not: Bool { 4 | True => False, 5 | False => True, 6 | } 7 | 8 | data Top { Unit } 9 | 10 | def Top.false : Bool { 11 | Unit => True.not 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/success/006.ir.expected: -------------------------------------------------------------------------------- 1 | def .foo(a, d) { Unit => d.match { MkD(a0) => MkD(a).match { MkD(x) => MkD(a) } } } 2 | -------------------------------------------------------------------------------- /test/suites/success/006.pol: -------------------------------------------------------------------------------- 1 | data A { MkA } 2 | data D(a: A) { MkD(a: A): D(a) } 3 | 4 | data Top { Unit } 5 | 6 | def Top.foo(a:A, d: D(a)): D(a) { 7 | Unit => d.match { 8 | MkD(a) => MkD(a).match { 9 | MkD(_) => MkD(a) 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/success/007.ir.expected: -------------------------------------------------------------------------------- 1 | def .foo { CTrue => Z } 2 | -------------------------------------------------------------------------------- /test/suites/success/007.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n : Nat )} 2 | data True {} 3 | data False {} 4 | 5 | data GADT(a : Type) { 6 | CTrue : GADT(True), 7 | CFalse : GADT(False), 8 | } 9 | 10 | def GADT(True).foo : Nat { 11 | CTrue => Z, 12 | CFalse absurd 13 | } -------------------------------------------------------------------------------- /test/suites/success/008.ir.expected: -------------------------------------------------------------------------------- 1 | def .id { Unit => comatch { .ap(x1) => x1 } } 2 | -------------------------------------------------------------------------------- /test/suites/success/008.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a: Type, b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | infix _ -> _ := Fun(_,_) 6 | 7 | data Top { Unit } 8 | 9 | def Top.id(a: Type): a -> a { 10 | Unit => \ap(_,_,x) => x 11 | } 12 | -------------------------------------------------------------------------------- /test/suites/success/009.ir.expected: -------------------------------------------------------------------------------- 1 | def .id { App(e) => App(e) } 2 | 3 | def .preservation(e2) { 4 | App(e) => comatch { .ap(h_eval) => h_eval.match { EBeta(f) => panic!("not yet implemented") } } 5 | } 6 | -------------------------------------------------------------------------------- /test/suites/success/009.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | data HasType(e: Exp) { 6 | TApp(e: Exp): HasType(App(e)), 7 | } 8 | 9 | data Exp { 10 | App(e: Exp) 11 | } 12 | 13 | data Eval(e1 e2: Exp) { 14 | EBeta(e: Exp): Eval(App(e), e), 15 | } 16 | 17 | def Exp.id: Exp { 18 | App(e) => App(e), 19 | } 20 | 21 | data Top { Unit } 22 | 23 | def (self: Exp).preservation(e2: Exp): Fun(Eval(self, e2), HasType(e2)) 24 | { 25 | App(e) => \ap(_,_,h_eval) => 26 | h_eval.match { 27 | EBeta(f) => ? : HasType(e) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/suites/success/010.ir.expected: -------------------------------------------------------------------------------- 1 | def .id { App(e) => App(e) } 2 | 3 | def .preservation(e2) { 4 | App(e) => comatch { .ap(h_eval) => h_eval.match { EBeta(f) => panic!("not yet implemented") } } 5 | } 6 | -------------------------------------------------------------------------------- /test/suites/success/010.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | data HasType(e: Exp) { 6 | TApp(e: Exp): HasType(App(e)), 7 | } 8 | 9 | data Exp { 10 | App(e: Exp) 11 | } 12 | 13 | data Eval(e1 e2: Exp) { 14 | EBeta(e: Exp): Eval(App(e), e.id), 15 | } 16 | 17 | def Exp.id: Exp { 18 | App(e) => App(e), 19 | } 20 | 21 | data Top { Unit } 22 | 23 | def (self: Exp).preservation(e2: Exp): Fun(Eval(self, e2), HasType(e2)) 24 | { 25 | App(e) => \ap(_,_,h_eval) => 26 | h_eval.match { 27 | EBeta(f) => ? : HasType(e.id) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/suites/success/011.ir.expected: -------------------------------------------------------------------------------- 1 | def .foo { Foo1 => True } 2 | -------------------------------------------------------------------------------- /test/suites/success/011.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | data Foo(b: Bool) { 4 | Foo1: Foo(True), 5 | Foo2: Foo(False), 6 | Foo3: Foo(False), 7 | Foo4: Foo(False), 8 | } 9 | 10 | def Foo(True).foo: Bool { 11 | Foo1 => True, 12 | Foo2 absurd, 13 | Foo3 absurd, 14 | Foo4 absurd, 15 | } 16 | -------------------------------------------------------------------------------- /test/suites/success/012.ir.expected: -------------------------------------------------------------------------------- 1 | codef MyFoo { .foo1 => True } 2 | -------------------------------------------------------------------------------- /test/suites/success/012.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | codata Foo(b: Bool) { 4 | Foo(True).foo1: Bool, 5 | Foo(False).foo2: Bool, 6 | Foo(False).foo3: Bool, 7 | Foo(False).foo4: Bool, 8 | } 9 | 10 | codef MyFoo: Foo(True) { 11 | .foo1 => True, 12 | .foo2 absurd, 13 | .foo3 absurd, 14 | .foo4 absurd 15 | } 16 | -------------------------------------------------------------------------------- /test/suites/success/013.ir.expected: -------------------------------------------------------------------------------- 1 | let add(x, y) { 2 | x.match { 3 | Z => y, 4 | S(x') => panic!("not yet implemented"), 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/suites/success/013.pol: -------------------------------------------------------------------------------- 1 | data Nat { 2 | Z, 3 | S(n: Nat), 4 | } 5 | 6 | let add(x y: Nat): Nat { 7 | x.match { 8 | Z => y, 9 | S(x') => ?, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/suites/success/014.ir.expected: -------------------------------------------------------------------------------- 1 | def .add(y) { 2 | Z => y, 3 | S(x') => S(x'.add(y)), 4 | } 5 | 6 | def .append'(n, m, ys) { 7 | Cons(n', x, xs) => Cons(n'.add(m), x, xs.append'(n', m, ys)), 8 | Nil => ys, 9 | } 10 | 11 | let append(n, m, xs, ys) { xs.append'(n, m, ys) } 12 | -------------------------------------------------------------------------------- /test/suites/success/014.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | def Nat.add(y: Nat) : Nat { 4 | Z => y, 5 | S(x') => S(x'.add(y)), 6 | } 7 | 8 | data Bool { True, False } 9 | 10 | data Vec(n: Nat) { 11 | Nil: Vec(Z), 12 | Cons(n: Nat, x: Bool, xs: Vec(n)): Vec(S(n)) 13 | } 14 | 15 | def Vec(n).append'(n m: Nat, ys: Vec(m)): Vec(n.add(m)) { 16 | Cons(n', x, xs) => Cons(n'.add(m), x, xs.append'(n', m, ys)), 17 | Nil => ys 18 | } 19 | 20 | let append(n m: Nat, xs: Vec(n), ys: Vec(m)): Vec(n.add(m)) { 21 | xs.append'(n, m, ys) 22 | } 23 | -------------------------------------------------------------------------------- /test/suites/success/015.ir.expected: -------------------------------------------------------------------------------- 1 | let transparentTwo { S(S(Z)) } 2 | 3 | let p2 { Refl(S(S(Z))) } 4 | -------------------------------------------------------------------------------- /test/suites/success/015.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | data Eq(a: Type, x y: a) { 4 | Refl(a: Type, x: a): Eq(a, x, x) 5 | } 6 | 7 | #[transparent] 8 | let transparentTwo: Nat {S(S(Z))} 9 | 10 | /// This proof typechecks 11 | let p2: Eq(Nat, S(S(Z)), transparentTwo) {Refl(Nat, S(S(Z)))} -------------------------------------------------------------------------------- /test/suites/success/016-named-args.ir.expected: -------------------------------------------------------------------------------- 1 | def .and(other) { 2 | True => other, 3 | False => False, 4 | } 5 | 6 | let example1 { Cons(True, Nil) } 7 | 8 | let example2 { True.and(False) } 9 | 10 | let example3 { None } 11 | -------------------------------------------------------------------------------- /test/suites/success/016-named-args.pol: -------------------------------------------------------------------------------- 1 | data Bool { True, False } 2 | 3 | def Bool.and(other: Bool): Bool { 4 | True => other, 5 | False => False 6 | } 7 | 8 | data List { 9 | Nil, 10 | Cons(head: Bool, tail: List) 11 | } 12 | 13 | data Option(elem: Type) { 14 | None(elem: Type): Option(elem), 15 | Some(elem: Type, x: elem): Option(elem), 16 | } 17 | 18 | let example1 : List { 19 | Cons(head := True, tail := Nil) 20 | } 21 | let example2: Bool { True.and(other := False) } 22 | let example3: Option(elem := Bool) { None(Bool) } 23 | -------------------------------------------------------------------------------- /test/suites/success/017.ir.expected: -------------------------------------------------------------------------------- 1 | let example1 { MkPair(True, False) } 2 | -------------------------------------------------------------------------------- /test/suites/success/017.pol: -------------------------------------------------------------------------------- 1 | data Pair(a b: Type) { 2 | MkPair(a b: Type,x: a, y: b) : Pair(a,b) 3 | } 4 | data Bool { True, False } 5 | 6 | let example1: Pair(Bool,Bool) { 7 | MkPair(_,_, True, False) 8 | } 9 | -------------------------------------------------------------------------------- /test/suites/success/018.ir.expected: -------------------------------------------------------------------------------- 1 | let example { None } 2 | -------------------------------------------------------------------------------- /test/suites/success/018.pol: -------------------------------------------------------------------------------- 1 | data Option(a: Type) { 2 | None(a: Type) : Option(a), 3 | Some(a:Type, x: a) : Option(a) 4 | } 5 | 6 | let example : Option(?) { None(?) } 7 | -------------------------------------------------------------------------------- /test/suites/success/019-absurd.ir.expected: -------------------------------------------------------------------------------- 1 | def .elim_zero { } 2 | 3 | def .elim { 4 | Ok(x) => x, 5 | Absurd(x) => x.elim_zero, 6 | } 7 | -------------------------------------------------------------------------------- /test/suites/success/019-absurd.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | data NotZero(n: Nat) { 4 | SNotZero(n: Nat): NotZero(S(n)) 5 | } 6 | 7 | def NotZero(Z).elim_zero(a: Type): a { SNotZero(n) absurd } 8 | 9 | data Bot { } 10 | 11 | data Foo(a: Type) { 12 | Ok(a: Type, x: a): Foo(a), 13 | Absurd(x: NotZero(Z)): Foo(Bot) 14 | } 15 | 16 | def Foo(a).elim(a: Type): a { 17 | Ok(a, x) => x, 18 | Absurd(x) => x.elim_zero(Bot) 19 | } 20 | -------------------------------------------------------------------------------- /test/suites/success/020-motive.ir.expected: -------------------------------------------------------------------------------- 1 | def .rep { 2 | T => TrueRep, 3 | F => FalseRep, 4 | } 5 | 6 | def .example(b) { 7 | Unit => 8 | b.match { 9 | T => TrueRep, 10 | F => FalseRep, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/success/020-motive.pol: -------------------------------------------------------------------------------- 1 | data Bool { 2 | T, 3 | F, 4 | } 5 | 6 | data BoolRep(x: Bool) { 7 | TrueRep: BoolRep(T), 8 | FalseRep: BoolRep(F), 9 | } 10 | 11 | def (self: Bool).rep: BoolRep(self) { 12 | T => TrueRep, 13 | F => FalseRep, 14 | } 15 | 16 | data Top { Unit } 17 | 18 | def Top.example(b: Bool): BoolRep(b) { 19 | Unit => b.match as x => BoolRep(x) { 20 | T => TrueRep, 21 | F => FalseRep, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/suites/success/021-evalorder.ir.expected: -------------------------------------------------------------------------------- 1 | def .diverge { Unit => Unit.diverge } 2 | 3 | def .before { Unit => Ignore(Unit.diverge) } 4 | 5 | def .after { Unit => comatch { .ap(x) => x } } 6 | 7 | codef Ignore(y) { .ap(x) => x } 8 | -------------------------------------------------------------------------------- /test/suites/success/021-evalorder.pol: -------------------------------------------------------------------------------- 1 | data Bool { 2 | T, 3 | F 4 | } 5 | 6 | codata Fun(a b: Type) { 7 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 8 | } 9 | 10 | codef Ignore(y: Bool): Fun(Bool, Bool) { 11 | .ap(a, b, x) => x 12 | } 13 | 14 | data Top { Unit } 15 | 16 | def Top.diverge : Bool { 17 | Unit => Unit.diverge 18 | } 19 | 20 | def Top.before : Fun(Bool, Bool) { 21 | Unit => Ignore(Unit.diverge) 22 | } 23 | 24 | def Top.after : Fun(Bool, Bool) { 25 | Unit => 26 | // let y = Unit.diverge in 27 | comatch Ignore2 { 28 | .ap(a, b, x) => x 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/suites/success/022-implicit-list.ir.expected: -------------------------------------------------------------------------------- 1 | let example { Cons(Unit, Nil) } 2 | -------------------------------------------------------------------------------- /test/suites/success/022-implicit-list.pol: -------------------------------------------------------------------------------- 1 | /// The type of finite lists. 2 | data List(implicit a: Type) { 3 | /// The canonical empty list. 4 | Nil(implicit a: Type): List(a:=a), 5 | /// Appending one element to the front of a list. 6 | Cons(implicit a: Type, x: a, xs: List(a:=a)): List(a:=a) 7 | } 8 | 9 | data Top { Unit } 10 | 11 | let example: List() {Cons(Unit, Nil())} 12 | -------------------------------------------------------------------------------- /test/suites/success/023-comatches.ir.expected: -------------------------------------------------------------------------------- 1 | def .id { Unit => comatch { .pi_elim(x0, a) => comatch { .ap(x3) => x3 } } } 2 | 3 | def .const { 4 | Unit => 5 | comatch { 6 | .pi_elim(x0, a) => 7 | comatch { .pi_elim(x2, b) => comatch { .ap(x5) => comatch { .ap(y) => x5 } } } 8 | } 9 | } 10 | 11 | codef IdType { .ap(a) => } 12 | -------------------------------------------------------------------------------- /test/suites/success/023-comatches.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a b: Type, x: a): b 3 | } 4 | 5 | infix _ -> _ := Fun(_,_) 6 | 7 | codata Pi(a: Type, p: a -> Type) { 8 | Pi(a, p).pi_elim(a: Type, p: a -> Type, x: a): p.ap(a, Type, x) 9 | } 10 | 11 | data Top { Unit } 12 | 13 | codef IdType: Fun(Type, Type) { .ap(_, _, a) => a -> a } 14 | 15 | def Top.id: Pi(Type, IdType) { 16 | Unit => (comatch { .pi_elim(_, _, a) => comatch { .ap(_, _, x) => x } }):Pi(Type, IdType) 17 | } 18 | 19 | def Top.const 20 | : Pi(Type, comatch { .ap(_, _, a) => Pi(Type, comatch { .ap(_, _, b) => a -> b -> a }) }) { 21 | Unit => 22 | comatch { 23 | .pi_elim(_, _, a) => 24 | comatch { 25 | .pi_elim(_, _, b) => comatch { .ap(_, _, x) => comatch { .ap(_, _, y) => x } } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/suites/success/024-gadt.ir.expected: -------------------------------------------------------------------------------- 1 | def .unwrap { 2 | WrapFoo(x) => x, 3 | WrapBar(x) => x, 4 | } 5 | -------------------------------------------------------------------------------- /test/suites/success/024-gadt.pol: -------------------------------------------------------------------------------- 1 | data Foo { MkFoo } 2 | 3 | data Bar { MkBar } 4 | 5 | data GADT(a: Type) { 6 | WrapFoo(x: Foo): GADT(Foo), 7 | WrapBar(x: Bar): GADT(Bar) 8 | } 9 | 10 | def GADT(a).unwrap(a: Type): a { 11 | WrapFoo(x) => x, 12 | WrapBar(x) => x 13 | } 14 | -------------------------------------------------------------------------------- /test/suites/success/025-imports.ir.expected: -------------------------------------------------------------------------------- 1 | use "../../../std/data/nat.pol" 2 | use "../../../std/data/bool.pol" 3 | 4 | def .iNeg { 5 | T => F, 6 | F => T, 7 | } 8 | 9 | let one { S(Z) } 10 | 11 | let true { T } 12 | -------------------------------------------------------------------------------- /test/suites/success/025-imports.pol: -------------------------------------------------------------------------------- 1 | use "../../../std/data/nat.pol" 2 | use "../../../std/data/bool.pol" 3 | 4 | let one: Nat { 1 } 5 | 6 | let true: Bool {T} 7 | 8 | def Bool.iNeg: Bool { 9 | T => F, 10 | F => T 11 | } 12 | -------------------------------------------------------------------------------- /test/suites/success/026-refinement.ir.expected: -------------------------------------------------------------------------------- 1 | def .sym(x, y) { Refl(x0) => Refl(y) } 2 | 3 | def .subst(x, y, p) { Refl(x0) => p } 4 | 5 | def .trans(x, y, z, h) { Refl(x0) => h } 6 | 7 | def .cong(x, y, f) { Refl(x0) => Refl(f.ap(y)) } 8 | 9 | def .not { 10 | True => False, 11 | False => True, 12 | } 13 | 14 | def .not_inverse { 15 | True => Refl(True), 16 | False => Refl(False), 17 | } 18 | -------------------------------------------------------------------------------- /test/suites/success/026-refinement.pol: -------------------------------------------------------------------------------- 1 | codata Prop(a: Type, x: a) { 2 | Prop(a, x).ap'(a: Type, x: a): Type 3 | } 4 | 5 | codata Fun(a b: Type) { 6 | Fun(a, b).ap(a b: Type, x: a): b 7 | } 8 | 9 | infix _ -> _ := Fun(_,_) 10 | 11 | data Eq(a: Type, x y: a) { 12 | Refl(a: Type, x: a): Eq(a, x, x) 13 | } 14 | 15 | def Eq(a, x, y).sym(a: Type, x y: a): Eq(a, y, x) { Refl(a, x) => Refl(a, x) } 16 | 17 | def Eq(a, x, y).subst(a: Type, x y: a, p: Prop(a, x)): Prop(a, y) { Refl(a, x) => p } 18 | 19 | def Eq(a, x, y).trans(a: Type, x y z: a, h: Eq(a, y, z)): Eq(a, x, z) { Refl(a, x) => h } 20 | 21 | def Eq(a, x, y).cong(a b: Type, x y: a, f: a -> b): Eq(b, f.ap(a, b, x), f.ap(a, b, y)) { 22 | Refl(a, x) => Refl(b, f.ap(a, b, x)) 23 | } 24 | 25 | data Bool { True, False } 26 | 27 | def Bool.not: Bool { 28 | True => False, 29 | False => True 30 | } 31 | 32 | def (self: Bool).not_inverse: Eq(Bool, self, self.not.not) { 33 | True => Refl(Bool, True), 34 | False => Refl(Bool, False) 35 | } 36 | -------------------------------------------------------------------------------- /test/suites/success/026-typedhole.ir.expected: -------------------------------------------------------------------------------- 1 | def .add(y) { 2 | Z => y, 3 | S(x') => S(x'.add(y)), 4 | } 5 | 6 | def .head(n) { Cons(n', x, xs) => panic!("not yet implemented") } 7 | 8 | def .tail(n) { Cons(n', x, xs) => panic!("not yet implemented") } 9 | 10 | def .append(n, m, ys) { 11 | Nil => ys, 12 | Cons(n', x, xs) => Cons(n'.add(m), x, xs.append(n', m, ys)), 13 | } 14 | 15 | def .example1 { Unit => Cons(S(Z), Z, Cons(Z, Z, Nil)) } 16 | 17 | def .example2 { Unit => Unit.example1.append(S(S(Z)), S(S(Z)), Unit.example1) } 18 | 19 | def .not { 20 | T => F, 21 | F => T, 22 | } 23 | 24 | def .if_then_else(then, else) { 25 | T => then, 26 | F => else, 27 | } 28 | 29 | codef Zeroes { 30 | .sHead => Z, 31 | .sTail => Zeroes, 32 | } 33 | 34 | codef Ones { 35 | .sHead => S(Z), 36 | .sTail => panic!("not yet implemented"), 37 | } 38 | 39 | codef Alternate(choose) { 40 | .sHead => choose.if_then_else(S(panic!("not yet implemented")), Z), 41 | .sTail => Alternate(choose.not), 42 | } 43 | -------------------------------------------------------------------------------- /test/suites/success/026-typedhole.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | def Nat.add(y: Nat): Nat { 4 | Z => y, 5 | S(x') => S(x'.add(y)) 6 | } 7 | 8 | data Vec(n: Nat) { 9 | Nil: Vec(Z), 10 | Cons(n x: Nat, xs: Vec(n)): Vec(S(n)) 11 | } 12 | 13 | def Vec(S(n)).head(n: Nat): Nat { 14 | Cons(n', x, xs) => ?, 15 | Nil absurd 16 | } 17 | 18 | def Vec(S(n)).tail(n: Nat): Vec(n) { 19 | Cons(n', x, xs) => ?, 20 | Nil absurd 21 | } 22 | 23 | def Vec(n).append(n m: Nat, ys: Vec(m)): Vec(n.add(m)) { 24 | Nil => ys, 25 | Cons(n', x, xs) => Cons(n'.add(m), x, xs.append(n', m, ys)) 26 | } 27 | 28 | data Top { Unit } 29 | 30 | def Top.example1: Vec(2) { Unit => Cons(1, 0, Cons(0, 0, Nil)) } 31 | 32 | def Top.example2: Vec(4) { 33 | Unit => Unit.example1.append(2, 2, Unit.example1) 34 | } 35 | 36 | data Bool { T, F } 37 | 38 | def Bool.not: Bool { 39 | T => F, 40 | F => T 41 | } 42 | 43 | def Bool.if_then_else(a: Type, then else: a): a { 44 | T => then, 45 | F => else 46 | } 47 | 48 | codata Stream { .sHead: Nat, .sTail: Stream } 49 | 50 | codef Zeroes: Stream { 51 | .sHead => Z, 52 | .sTail => Zeroes 53 | } 54 | 55 | codef Ones: Stream { 56 | .sHead => S(Z), 57 | .sTail => ? 58 | } 59 | 60 | codef Alternate(choose: Bool): Stream { 61 | .sHead => choose.if_then_else(Nat, S(?), Z), 62 | .sTail => Alternate(choose.not) 63 | } 64 | -------------------------------------------------------------------------------- /test/suites/success/027-colist.ir.expected: -------------------------------------------------------------------------------- 1 | def .pred { 2 | Z => Z, 3 | S(n) => n, 4 | Omega => Omega, 5 | } 6 | 7 | codef CountUp(from) { 8 | .head(n, p) => from, 9 | .tail(n) => CountUp(S(from)), 10 | } 11 | 12 | codef TakeN(n, s) { 13 | .head(n', p) => s.head(Omega, OmegaNotZero), 14 | .tail(n') => TakeN(n.pred, s.tail(Omega)), 15 | } 16 | -------------------------------------------------------------------------------- /test/suites/success/027-colist.pol: -------------------------------------------------------------------------------- 1 | data CoNat { Z, S(n: CoNat), Omega } 2 | 3 | data NotZero(n: CoNat) { 4 | SNotZero(n: CoNat): NotZero(S(n)), 5 | OmegaNotZero: NotZero(Omega) 6 | } 7 | 8 | def CoNat.pred: CoNat { 9 | Z => Z, 10 | S(n) => n, 11 | Omega => Omega 12 | } 13 | 14 | codata CoList(n: CoNat) { 15 | CoList(n).head(n: CoNat, p: NotZero(n)): CoNat, 16 | CoList(n).tail(n: CoNat): CoList(n.pred) 17 | } 18 | 19 | codef CountUp(from: CoNat): CoList(Omega) { 20 | .head(n, p) => from, 21 | .tail(n) => CountUp(S(from)) 22 | } 23 | 24 | codef TakeN(n: CoNat, s: CoList(Omega)): CoList(n) { 25 | .head(n', p) => s.head(Omega, OmegaNotZero), 26 | .tail(n') => TakeN(n.pred, s.tail(Omega)) 27 | } 28 | -------------------------------------------------------------------------------- /test/suites/success/028-boolrep.ir.expected: -------------------------------------------------------------------------------- 1 | use "../../../std/data/bool.pol" 2 | 3 | def .extract(x) { 4 | TrueRep => T, 5 | FalseRep => F, 6 | } 7 | 8 | def .flipRep(x, rep) { 9 | Unit => 10 | rep.match { 11 | TrueRep => FalseRep, 12 | FalseRep => TrueRep, 13 | } 14 | } 15 | 16 | def .example { Unit => Unit.flipRep(T, TrueRep).extract(F) } 17 | -------------------------------------------------------------------------------- /test/suites/success/028-boolrep.pol: -------------------------------------------------------------------------------- 1 | use "../../../std/data/bool.pol" 2 | 3 | data BoolRep(x: Bool) { 4 | TrueRep: BoolRep(T), 5 | FalseRep: BoolRep(F), 6 | } 7 | 8 | def BoolRep(x).extract(x: Bool): Bool { 9 | TrueRep => T, 10 | FalseRep => F, 11 | } 12 | 13 | data Top { Unit } 14 | 15 | def Top.flipRep(x: Bool, rep: BoolRep(x)): BoolRep(x.neg) { 16 | Unit => rep.match { 17 | TrueRep => FalseRep, 18 | FalseRep => TrueRep, 19 | } 20 | } 21 | 22 | def Top.example: Bool { 23 | Unit => Unit.flipRep(T, TrueRep).extract(F) 24 | } 25 | -------------------------------------------------------------------------------- /test/suites/success/029-arith.ir.expected: -------------------------------------------------------------------------------- 1 | def .add(y) { 2 | Z => y, 3 | S(x') => S(x'.add(y)), 4 | } 5 | 6 | def .and(y) { 7 | T => y, 8 | F => F, 9 | } 10 | 11 | def .preserves(e1, e2, t, h1) { 12 | EAddCongL(lhs, lhs', rhs, h_lhs) => panic!("not yet implemented"), 13 | EAddCongR(lhs, rhs, rhs', h_rhs) => panic!("not yet implemented"), 14 | EAddRed(n1, n2) => panic!("not yet implemented"), 15 | EIsZeroCong(e, e', h_e) => panic!("not yet implemented"), 16 | EAndCongL(lhs, lhs', rhs, h_lhs) => panic!("not yet implemented"), 17 | EAndCongR(lhs, rhs, rhs', h_rhs) => panic!("not yet implemented"), 18 | EAndRed(b1, b2) => panic!("not yet implemented"), 19 | } 20 | 21 | let example { And(IsZero(Add(Num(Z), Num(Z))), Boo(T)) } 22 | 23 | let example_has_type { 24 | TAnd(IsZero(Add(Num(Z), Num(Z))), 25 | Boo(T), 26 | TIsZero(Add(Num(Z), Num(Z)), TAdd(Num(Z), Num(Z), TNum(Z), TNum(Z))), 27 | TBoo(T)) 28 | } 29 | -------------------------------------------------------------------------------- /test/suites/success/030-buffer.ir.expected: -------------------------------------------------------------------------------- 1 | def .head(n) { Cons(n', x, xs) => x } 2 | 3 | def .tail(n) { Cons(n', x, xs) => xs } 4 | 5 | codef Empty { } 6 | 7 | codef FromVec(n, xs) { 8 | .read(n') => 9 | comatch { 10 | .proj1 => xs.head(n'), 11 | .proj2 => FromVec(n', xs.tail(n')), 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/suites/success/030-buffer.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | data Bool { T, F } 4 | 5 | codata Pair(a b: Type) { 6 | Pair(a, b).proj1(a b: Type): a, 7 | Pair(a, b).proj2(a b: Type): b 8 | } 9 | 10 | data Vec(n: Nat) { 11 | Nil: Vec(Z), 12 | Cons(n: Nat, x: Bool, xs: Vec(n)): Vec(S(n)) 13 | } 14 | 15 | def Vec(S(n)).head(n: Nat): Bool { 16 | Cons(n', x, xs) => x, 17 | Nil absurd 18 | } 19 | 20 | def Vec(S(n)).tail(n: Nat): Vec(n) { 21 | Cons(n', x, xs) => xs, 22 | Nil absurd 23 | } 24 | 25 | codata Buffer(n: Nat) { 26 | Buffer(S(n)).read(n: Nat): Pair(Bool, Buffer(n)) 27 | } 28 | 29 | codef Empty: Buffer(Z) { .read(n) absurd } 30 | 31 | codef FromVec(n: Nat, xs: Vec(n)): Buffer(n) { 32 | .read(n') => 33 | comatch { 34 | .proj1(_, _) => xs.head(n'), 35 | .proj2(_, _) => FromVec(n', xs.tail(n')) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/suites/success/031-classical-logic.ir.expected: -------------------------------------------------------------------------------- 1 | def .contra(prf, ref) { Unit => ref.ret(prf) } 2 | 3 | def .lem { 4 | Unit => 5 | comatch { 6 | .given(k) => Unit.contra(Right(comatch { .ret(x1) => Unit.contra(Left(x1), k) }), k) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/suites/success/031-classical-logic.pol: -------------------------------------------------------------------------------- 1 | data False { } 2 | 3 | codata Not(a: Type) { 4 | Not(a).ret(a: Type, x: a): False 5 | } 6 | 7 | codata DN(a: Type) { 8 | DN(a).given(a: Type, x: Not(a)): False 9 | } 10 | 11 | data Or(a b: Type) { 12 | Left(a b: Type, x: a): Or(a, b), 13 | Right(a b: Type, x: b): Or(a, b) 14 | } 15 | 16 | data Top { Unit } 17 | 18 | def Top.contra(a: Type, prf: a, ref: Not(a)): False { Unit => ref.ret(a, prf) } 19 | 20 | def Top.lem(a: Type): DN(Or(a, Not(a))) { 21 | Unit => 22 | comatch C1 { 23 | .given(_, k) => 24 | Unit.contra(Or(a, Not(a)), 25 | Right(a, 26 | Not(a), 27 | comatch C2 { 28 | .ret(_, x) => 29 | Unit.contra(Or(a, Not(a)), Left(a, Not(a), x), k) 30 | }), 31 | k) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/suites/success/032-expressions-case-study.ir.expected: -------------------------------------------------------------------------------- 1 | def .pres(e, ty) { 2 | TTrue => comatch { .preservationStep(e1, e2, ty0, s) => s.d_step1(e2) }, 3 | TFalse => comatch { .preservationStep(e1, e2, ty0, s) => s.d_step3(e2) }, 4 | TIte(e1, e2, e3, ty0, t1, t2, t3) => 5 | comatch { .preservationStep(e4, e5, ty1, s) => s.d_step5(e1, e2, e3, e5, ty, t1, t2, t3) }, 6 | } 7 | 8 | codef StIteT(e1, e2) { .d_step5(e3, e4, e5, e6, ty, t1, t2, t3) => t2 } 9 | 10 | codef StIteF(e1, e2) { .d_step5(e3, e4, e5, e6, ty, t1, t2, t3) => t3 } 11 | 12 | codef StIte(e1, e2, e3, e4, s) { 13 | .d_step5(e1', e2', e3', e5', ty, t1, t2, t3) => 14 | TIte(e2, e3, e4, ty, t1.pres(e1, TyBool).preservationStep(e1, e2, TyBool, s), t2, t3) 15 | } 16 | -------------------------------------------------------------------------------- /test/suites/success/033-setoid.ir.expected: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polarity-lang/polarity/763c7f2e47e1adff6f48680946aeacb65e9af923/test/suites/success/033-setoid.ir.expected -------------------------------------------------------------------------------- /test/suites/success/033-setoid.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a b: Type, x: a): b 3 | } 4 | 5 | infix _ -> _ := Fun(_,_) 6 | 7 | codata Setoid { .type: Type, (self: Setoid).equality: self.type -> self.type -> Type } 8 | 9 | codata SetoidFun(a b: Setoid) { 10 | (self: SetoidFun(a, b)).s_ap(a b: Setoid, x: a.type): b.type, 11 | (self: SetoidFun(a, b)).s_ap_eq(a b: Setoid, 12 | x y: a.type, 13 | p: a.equality.ap(a.type, a.type -> Type, x).ap(a.type, Type, y) 14 | ) 15 | : self.s_ap(a, b, x) 16 | } 17 | -------------------------------------------------------------------------------- /test/suites/success/034-local-matches.ir.expected: -------------------------------------------------------------------------------- 1 | def .top_is_zero(n) { 2 | Unit => 3 | n.match { 4 | Z => T, 5 | S(n0) => F, 6 | } 7 | } 8 | 9 | def .top_id { Unit => comatch { .ap(x) => x } } 10 | -------------------------------------------------------------------------------- /test/suites/success/034-local-matches.pol: -------------------------------------------------------------------------------- 1 | data Nat { 2 | Z, 3 | S(n: Nat) 4 | } 5 | 6 | data Bool { 7 | T, 8 | F 9 | } 10 | 11 | codata Fun(a b: Type) { 12 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 13 | } 14 | 15 | data Top { 16 | Unit 17 | } 18 | 19 | def Top.top_is_zero(n: Nat): Bool { 20 | Unit => n.match is_zero { 21 | Z => T, 22 | S(n) => F, 23 | } 24 | } 25 | 26 | def Top.top_id(a: Type): Fun(a, a) { 27 | Unit => comatch Id { 28 | .ap(a, b, x) => x 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/suites/success/036-webserver.ir.expected: -------------------------------------------------------------------------------- 1 | def .cong_pair(a, b, c) { Refl(x0) => Refl(Pair(b, c)) } 2 | 3 | codef Pair(x, y) { 4 | .fst => x, 5 | .snd => y, 6 | } 7 | 8 | codef MkUtils { .put_twice(n, route, state) => route.put(n).ap(route.put(n).ap(state).fst) } 9 | 10 | codef Index { 11 | .requiresLogin => F, 12 | .post => 13 | comatch { 14 | .ap(state) => 15 | comatch { 16 | .fst => state, 17 | .snd => Forbidden, 18 | } 19 | }, 20 | .get => comatch { .ap(state) => Return(state.counter(F)) }, 21 | .put(n) => comatch { .ap(state) => Pair(state, Forbidden) }, 22 | .put_idempotent(n) => comatch { .dap(x0, state) => Refl(Pair(state, Forbidden)) }, 23 | } 24 | 25 | codef Admin { 26 | .requiresLogin => T, 27 | .post => 28 | comatch { 29 | .ap(state) => 30 | comatch { 31 | .fst => state.increment, 32 | .snd => Return(state.increment.counter(T)), 33 | } 34 | }, 35 | .get => comatch { .ap(state) => Return(state.counter(T)) }, 36 | .put(n) => comatch { .ap(state) => Pair(state.set(n), Return(n)) }, 37 | .put_idempotent(n) => 38 | comatch { 39 | .dap(x0, state) => 40 | state.set_idempotent(T, n).cong_pair(state.set(n), state.set(n).set(n), Return(n)) 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /test/suites/success/037-vect.ir.expected: -------------------------------------------------------------------------------- 1 | def .add(y) { 2 | Z => y, 3 | S(x') => S(x'.add(y)), 4 | } 5 | 6 | def .head(n) { Cons(n', x, xs) => x } 7 | 8 | def .tail(n) { Cons(n', x, xs) => xs } 9 | 10 | def .append(n, m, ys) { 11 | Nil => ys, 12 | Cons(n', x, xs) => Cons(n'.add(m), x, xs.append(n', m, ys)), 13 | } 14 | 15 | def .example1 { Unit => Cons(S(Z), Z, Cons(Z, Z, Nil)) } 16 | 17 | let main { Unit.example1.append(S(S(Z)), S(S(Z)), Unit.example1) } 18 | -------------------------------------------------------------------------------- /test/suites/success/037-vect.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | def Nat.add(y: Nat): Nat { 4 | Z => y, 5 | S(x') => S(x'.add(y)) 6 | } 7 | 8 | data Vec(n: Nat) { 9 | Nil: Vec(Z), 10 | Cons(n x: Nat, xs: Vec(n)): Vec(S(n)) 11 | } 12 | 13 | def Vec(S(n)).head(n: Nat): Nat { 14 | Cons(n', x, xs) => x, 15 | Nil absurd 16 | } 17 | 18 | def Vec(S(n)).tail(n: Nat): Vec(n) { 19 | Cons(n', x, xs) => xs, 20 | Nil absurd 21 | } 22 | 23 | def Vec(n).append(n m: Nat, ys: Vec(m)): Vec(n.add(m)) { 24 | Nil => ys, 25 | Cons(n', x, xs) => Cons(n'.add(m), x, xs.append(n', m, ys)) 26 | } 27 | 28 | data Top { Unit } 29 | 30 | def Top.example1: Vec(2) { Unit => Cons(1, 0, Cons(0, 0, Nil)) } 31 | 32 | let main: Vec(4) {Unit.example1.append(2, 2, Unit.example1)} 33 | -------------------------------------------------------------------------------- /test/suites/success/038-erase-hole.ir.expected: -------------------------------------------------------------------------------- 1 | use "../../../std/data/list.pol" 2 | use "../../../std/data/nat.pol" 3 | 4 | let foo(a) { Nil } 5 | 6 | let bar { foo() } 7 | -------------------------------------------------------------------------------- /test/suites/success/038-erase-hole.pol: -------------------------------------------------------------------------------- 1 | use "../../../std/data/list.pol" 2 | use "../../../std/data/nat.pol" 3 | 4 | /// FIXME: At the moment, a is not erased. 5 | let foo(a: _) : List(a) { Nil(a) } 6 | 7 | let bar: List(Nat) { foo(Nat) } 8 | -------------------------------------------------------------------------------- /test/suites/success/039-metavars-accross-decls.ir.expected: -------------------------------------------------------------------------------- 1 | let foo { T } 2 | 3 | let bar { Refl(T) } 4 | -------------------------------------------------------------------------------- /test/suites/success/039-metavars-accross-decls.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | data Eq(a: Type, x y: a) { 4 | Refl(a: Type, x: a): Eq(a, x, x) 5 | } 6 | 7 | #[transparent] 8 | let foo: Bool { _ } 9 | 10 | let bar: Eq(Bool, foo(), T) { 11 | Refl(Bool, T) 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/success/040-absurd-lam.ir.expected: -------------------------------------------------------------------------------- 1 | let example { comatch { } } 2 | -------------------------------------------------------------------------------- /test/suites/success/040-absurd-lam.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | codata Foo(b: Bool) { 4 | Foo(T).d(x: Bool): Bool 5 | } 6 | 7 | let example: Foo(F) {\d(_) absurd} 8 | -------------------------------------------------------------------------------- /test/suites/success/041-eta-comatch.ir.expected: -------------------------------------------------------------------------------- 1 | codef f { .ap(x) => comatch { .test(x0) => x0 } } 2 | 3 | let eq { Refl(f.ap(T)) } 4 | -------------------------------------------------------------------------------- /test/suites/success/041-eta-comatch.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a b: Type) { 2 | Fun(a, b).ap(a b: Type, x: a): b, 3 | } 4 | 5 | data Eq(a: Type, x y: a) { 6 | Refl(a: Type, x: a): Eq(a, x, x), 7 | } 8 | 9 | data Bool { T, F } 10 | 11 | codata Test { .test(x: Bool): Bool } 12 | 13 | codef f: Fun(Bool, Test) { .ap(Bool, Bool, _) => comatch { .test(x) => x } } 14 | 15 | let eq: Eq(Test, f.ap(Bool, Test, T), f.ap(Bool, Test, F)) {Refl(Test, 16 | f.ap(Bool, Test, T))} -------------------------------------------------------------------------------- /test/suites/success/Regr-137.ir.expected: -------------------------------------------------------------------------------- 1 | def .ind(P, step) { 2 | True => panic!("not yet implemented"), 3 | False => panic!("not yet implemented"), 4 | } 5 | -------------------------------------------------------------------------------- /test/suites/success/Regr-137.pol: -------------------------------------------------------------------------------- 1 | codata Fun(A B: Type) { 2 | Fun(A,B).ap(A B: Type, x: A): B 3 | } 4 | 5 | infix _ -> _ := Fun(_,_) 6 | 7 | codata Pi(T: Fun(Bool, Type)) { 8 | Pi(T).dap(T: Fun(Bool,Type), x: Bool): T.ap(Bool,Type,x) 9 | } 10 | 11 | data Bool { True, False } 12 | 13 | def Bool.ind( P: Fun(Bool,Type) 14 | , step: Pi(comatch { .ap(_,_,x) => P.ap(Bool,Type,x) -> P.ap(Bool,Type,x) }) 15 | ) : Bool { 16 | True => ?, 17 | False => ? 18 | } 19 | -------------------------------------------------------------------------------- /test/suites/success/Regr-230.ir.expected: -------------------------------------------------------------------------------- 1 | def .add(m) { 2 | Z => m, 3 | S(n) => S(n.add(m)), 4 | } 5 | 6 | let two { S(S(Z)) } 7 | 8 | let foo { Refl(two.add(S(S(Z)))) } 9 | -------------------------------------------------------------------------------- /test/suites/success/Regr-230.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | def Nat.add(m: Nat): Nat { 4 | Z => m, 5 | S(n) => S(n.add(m)) 6 | } 7 | 8 | let two: Nat {S(S(Z))} 9 | 10 | data Eq(a: Type, x y: a) { 11 | Refl(a: Type, x: a): Eq(a, x, x) 12 | } 13 | 14 | // The "two" is opaque, so shouldn't be normalized, but the expressions should be equal nonetheless. 15 | let foo : Eq(Nat, two.add(S(S(Z))), two.add(S(S(Z)))) { Refl(Nat, two.add(S(S(Z))))} 16 | -------------------------------------------------------------------------------- /test/suites/success/Regr-230b.ir.expected: -------------------------------------------------------------------------------- 1 | def .add(m) { 2 | Z => m, 3 | S(n) => S(n.add(m)), 4 | } 5 | 6 | let two { S(S(Z)) } 7 | 8 | let foo { Refl(two.add(S(S(Z)))) } 9 | -------------------------------------------------------------------------------- /test/suites/success/Regr-230b.pol: -------------------------------------------------------------------------------- 1 | data Nat { Z, S(n: Nat) } 2 | 3 | def Nat.add(m: Nat): Nat { 4 | Z => m, 5 | S(n) => S(n.add(m)) 6 | } 7 | 8 | #[transparent] 9 | let two: Nat {S(S(Z))} 10 | 11 | data Eq(a: Type, x y: a) { 12 | Refl(a: Type, x: a): Eq(a, x, x) 13 | } 14 | 15 | let foo : Eq(Nat, two.add(S(S(Z))), S(S(S(S(Z))))) { Refl(Nat, two.add(S(S(Z))))} 16 | -------------------------------------------------------------------------------- /test/suites/success/Regr-250.ir.expected: -------------------------------------------------------------------------------- 1 | codef Unit { } 2 | -------------------------------------------------------------------------------- /test/suites/success/Regr-250.pol: -------------------------------------------------------------------------------- 1 | data Nat { 2 | Z, 3 | S(n: Nat), 4 | } 5 | 6 | data Fin(max: Nat) { 7 | FZ(max: Nat): Fin(max), 8 | FS(max: Nat, val: Fin(max)): Fin(S(max)), 9 | } 10 | 11 | codata ProductN(arity: Nat) { 12 | ProductN(S(arity)).typeAt(arity: Nat, pos: Fin(arity)): Type, 13 | (self: ProductN(S(arity))).dataAt(arity: Nat, pos: Fin(arity)): self.typeAt(arity, pos), 14 | } 15 | 16 | codef Unit: ProductN(0) { 17 | .typeAt(_, _) absurd, 18 | .dataAt(_, _) absurd, 19 | } 20 | -------------------------------------------------------------------------------- /test/suites/success/Regr-271.ir.expected: -------------------------------------------------------------------------------- 1 | codef S(n) { .add(m) => n.add(S(m)) } 2 | 3 | codef Z { .add(m) => m } 4 | 5 | let test { Refl(S(S(S(S(Z))))) } 6 | -------------------------------------------------------------------------------- /test/suites/success/Regr-271.pol: -------------------------------------------------------------------------------- 1 | codata Nat { .add(m: Nat): Nat } 2 | 3 | codef S(n: Nat): Nat { .add(m) => n.add(S(m)) } 4 | 5 | codef Z: Nat { .add(m) => m } 6 | 7 | 8 | 9 | data Eq(a: Type, x y : a) { 10 | Refl(a: Type, x: a) : Eq(a,x,x) 11 | } 12 | 13 | let test : Eq(Nat, 4, 2.add(2)) { 14 | Refl(Nat, 4) 15 | } -------------------------------------------------------------------------------- /test/suites/success/Regr-297.ir.expected: -------------------------------------------------------------------------------- 1 | codef Id { .ap(x1) => x1 } 2 | 3 | let example { Id.ap(Unit) } 4 | -------------------------------------------------------------------------------- /test/suites/success/Regr-297.pol: -------------------------------------------------------------------------------- 1 | codata Fun(implicit a b: Type) { 2 | Fun(a:=a,b:=b).ap(implicit a b: Type, x: a): b 3 | } 4 | 5 | codef Id(implicit a: Type) : Fun(a:=a, b:=a) { 6 | .ap(_,_,x) => x 7 | } 8 | 9 | data Top { Unit } 10 | 11 | let example: Top { Id.ap(Unit) } 12 | -------------------------------------------------------------------------------- /test/suites/success/Regr-341a.ir.expected: -------------------------------------------------------------------------------- 1 | codef F { .ap(x1) => } 2 | 3 | let foo(x) { panic!("not yet implemented") } 4 | 5 | let T { foo(comatch { .ap(x1) => F.ap(x1) }) } 6 | -------------------------------------------------------------------------------- /test/suites/success/Regr-341a.pol: -------------------------------------------------------------------------------- 1 | data Top { Unit } 2 | 3 | codata Fun(a b: Type) { 4 | Fun(a,b).ap(a b: Type, x: a) : b 5 | } 6 | 7 | codef F: Fun(Type, Type) { 8 | .ap(_,_,x) => Type 9 | } 10 | 11 | let foo(t: Type, x: Fun(t, Type)): Type { 12 | ? 13 | } 14 | 15 | let T : Type { 16 | foo(F.ap(Type, Type, (? : Type)), \ap(_,_,x) => F.ap(Type, Type, x)) 17 | } 18 | -------------------------------------------------------------------------------- /test/suites/success/Regr-341b.ir.expected: -------------------------------------------------------------------------------- 1 | def .foo { Bar => T } 2 | -------------------------------------------------------------------------------- /test/suites/success/Regr-341b.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | data Foo(b: Bool) { 4 | Bar: Foo(T), 5 | Baz: Foo(F) 6 | } 7 | 8 | /// Ensure unification with type annotations works 9 | def Foo((T):Bool).foo: Bool { 10 | Bar => T, 11 | Baz absurd 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/success/Regr-341c.ir.expected: -------------------------------------------------------------------------------- 1 | def .neg { 2 | T => F, 3 | F => T, 4 | } 5 | 6 | let foo { comatch { .ap(x) => x.neg } } 7 | 8 | let bar { Refl(F) } 9 | -------------------------------------------------------------------------------- /test/suites/success/Regr-341c.pol: -------------------------------------------------------------------------------- 1 | data Bool { T, F } 2 | 3 | data Eq(x y: Bool) { 4 | Refl(x: Bool): Eq(x, x) 5 | } 6 | 7 | codata Fun { 8 | .ap(x: Bool): Bool 9 | } 10 | 11 | def Bool.neg: Bool { 12 | T => F, 13 | F => T, 14 | } 15 | 16 | /// Annotations can occur in neutral expressions 17 | #[transparent] 18 | let foo: Fun { 19 | comatch { 20 | .ap(x) =>(x: Bool).neg 21 | } 22 | } 23 | 24 | let bar: Eq(foo.ap(T), F) { 25 | Refl(F) 26 | } 27 | -------------------------------------------------------------------------------- /test/suites/success/Regr-348.ir.expected: -------------------------------------------------------------------------------- 1 | codef Id { .ap(x) => x } 2 | -------------------------------------------------------------------------------- /test/suites/success/Regr-348.pol: -------------------------------------------------------------------------------- 1 | codata Fun(a: Type, b: Type) { 2 | Fun(a, b).ap(a: Type, b: Type, x: a) : b 3 | } 4 | 5 | codef Id(a: Type): Fun(a, ?) { 6 | .ap(a, b, x) => x 7 | } 8 | -------------------------------------------------------------------------------- /test/suites/success/Regr-403.ir.expected: -------------------------------------------------------------------------------- 1 | use "../../../std/data/eq.pol" 2 | use "../../../std/data/bool.pol" 3 | use "../../../std/codata/fun.pol" 4 | 5 | let foo { comatch { .ap(x1) => x1 } } 6 | 7 | let proof { Refl(foo) } 8 | -------------------------------------------------------------------------------- /test/suites/success/Regr-403.pol: -------------------------------------------------------------------------------- 1 | use "../../../std/data/eq.pol" 2 | use "../../../std/data/bool.pol" 3 | use "../../../std/codata/fun.pol" 4 | 5 | #[transparent] 6 | let foo : Fun(Bool, Bool) { 7 | \ap(_,_,x) => x 8 | } 9 | 10 | let proof: Eq(a := Fun(Bool, Bool), foo, foo) { 11 | Refl(a:= Fun(Bool,Bool), foo) 12 | } 13 | -------------------------------------------------------------------------------- /test/suites/success/Regr-442.ir.expected: -------------------------------------------------------------------------------- 1 | let force(f, x) { f.foo(x) } 2 | -------------------------------------------------------------------------------- /test/suites/success/Regr-442.pol: -------------------------------------------------------------------------------- 1 | codata Foo { 2 | (f: Foo).foo(a: Type, x: ?): a 3 | } 4 | 5 | let force(f: Foo, b: Type, x: b): b { 6 | f.foo(b, x) 7 | } 8 | -------------------------------------------------------------------------------- /test/suites/success/suite.toml: -------------------------------------------------------------------------------- 1 | description = "Tests which succeed" 2 | -------------------------------------------------------------------------------- /test/test-runner/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test-runner" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | autobins = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | # async 12 | tokio = { version = "1", features = ["rt-multi-thread"] } 13 | # cli 14 | clap = { version = "4", features = ["derive"] } 15 | # full text search engine 16 | tantivy = "0.18" 17 | # url (for file locations) 18 | url = { workspace = true } 19 | # Logging infrastructure 20 | env_logger = { workspace = true } 21 | log = { workspace = true } 22 | # error handling 23 | miette = { workspace = true, features = ["fancy"] } 24 | # config 25 | serde = "1" 26 | serde_derive = "1" 27 | toml = "0.5" 28 | # Colored output 29 | termcolor = { version = "1.4.1" } 30 | # Find files recursively 31 | walkdir = "2.5.0" 32 | # workspace members 33 | ast = { path = "../../lang/ast" } 34 | parser = { path = "../../lang/parser" } 35 | elaborator = { path = "../../lang/elaborator" } 36 | printer = { path = "../../lang/printer" } 37 | driver = { path = "../../lang/driver" } 38 | 39 | [[test]] 40 | name = "integration" 41 | path = "src/main.rs" 42 | harness = false 43 | -------------------------------------------------------------------------------- /web/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /web/.eslintrc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | parser: "@typescript-eslint/parser" 3 | plugins: 4 | - "@typescript-eslint" 5 | extends: 6 | - eslint:recommended 7 | - plugin:prettier/recommended 8 | - prettier 9 | overrides: 10 | - files: "webpack.config.js" 11 | env: 12 | "node": true 13 | - files: ["*.ts", "*.tsx"] 14 | extends: 15 | - plugin:@typescript-eslint/eslint-recommended 16 | - plugin:@typescript-eslint/recommended-requiring-type-checking 17 | - plugin:@typescript-eslint/recommended 18 | rules: 19 | "@typescript-eslint/no-inferrable-types": ["off"] 20 | parserOptions: 21 | project: 22 | - "./tsconfig.json" 23 | - "./packages/app/tsconfig.json" 24 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /web/.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | bracketSpacing: true 3 | printWidth: 120 4 | semi: true 5 | singleQuote: false 6 | tabWidth: 2 7 | trailingComma: all 8 | useTabs: false 9 | overrides: 10 | - files: "*.ts" 11 | options: 12 | parser: typescript 13 | -------------------------------------------------------------------------------- /web/.stylelintignore: -------------------------------------------------------------------------------- 1 | packages/app/assets/hljs-vs-dark.css 2 | packages/app/assets/hljs-vs-light.css 3 | -------------------------------------------------------------------------------- /web/.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard" 3 | } 4 | -------------------------------------------------------------------------------- /web/Makefile: -------------------------------------------------------------------------------- 1 | deps: 2 | @rustup target add wasm32-unknown-unknown 3 | @cargo install -f wasm-bindgen-cli --version 0.2.100 4 | @npm install 5 | 6 | build: build-server build-app 7 | 8 | run: clean-app build-server 9 | @npm run app --workspace=packages/app 10 | 11 | build-server: clean-app 12 | @CARGO_PROFILE_CODEGEN_UNITS=1 CARGO_PROFILE_RELEASE_OPT_LEVEL=z CARGO_PROFILE_RELEASE_LTO=fat cargo build -p lsp-browser --target wasm32-unknown-unknown --release 13 | @wasm-bindgen --out-dir ./packages/app/assets/wasm --target web --typescript ../target/wasm32-unknown-unknown/release/lsp_browser.wasm 14 | 15 | build-app: 16 | @npm run build --workspace=packages/app 17 | 18 | clean: clean-server clean-app 19 | 20 | clean-server: 21 | @cargo clean 22 | 23 | clean-app: 24 | @rm -rf packages/app/dist 25 | @rm -rf packages/app/assets/wasm 26 | 27 | lint: 28 | @cargo fmt --all --check 29 | @cargo clippy --all -- -Dwarnings 30 | @npm run lint --workspace=packages/app 31 | @npx stylelint "**/*.css" 32 | 33 | format: 34 | @cargo fmt --all 35 | @npm run format --workspace=packages/app 36 | @npx stylelint "**/*.css" --fix 37 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # Web Demo 2 | 3 | Based on [tower-lsp-web-demo](https://github.com/silvanshade/tower-lsp-web-demo/), commit `d629bf80cab03e8f87dcd5821e1307c204ca6a9e`. 4 | 5 | ## Requirements 6 | 7 | * [Rust and Cargo](https://www.rust-lang.org/tools/install) 8 | * [Node.js](https://nodejs.org/en/download) and [npm](https://www.npmjs.com/package/npm) 9 | 10 | ## Build 11 | 12 | ```sh 13 | make deps 14 | make build 15 | ``` 16 | 17 | ## Run 18 | 19 | To run the web demo, execute the following command: 20 | 21 | ```sh 22 | make run 23 | ``` 24 | 25 | Then, navigate to [http://localhost:9000/editor#example.pol](http://localhost:9000/editor#example.pol), where `example.pol` can be any file in the `examples` directory. 26 | 27 | ## Troubleshooting 28 | 29 | If you experience the following error: 30 | 31 | ``` 32 | FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory 33 | ``` 34 | 35 | consider increasing the heap size, e.g. by setting the `NODE_OPTIONS` environment variable: 36 | 37 | ```sh 38 | export NODE_OPTIONS=--max-old-space-size=4096 39 | ``` 40 | 41 | ## License 42 | 43 | The content in this folder is based on [tower-lsp-web-demo](https://github.com/silvanshade/tower-lsp-web-demo/) by Darin Morrison. 44 | Like the rest of the project, it is licensed under the terms of both the MIT license and the Apache License 2.0. 45 | See [LICENSE-APACHE](../LICENSE-APACHE) and [LICENSE-MIT](../LICENSE-MIT) for details. 46 | -------------------------------------------------------------------------------- /web/crates/browser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | publish = false 3 | edition = "2024" 4 | name = "lsp-browser" 5 | version = "0.0.0" 6 | 7 | [features] 8 | default = ["tower-lsp-server/runtime-agnostic"] 9 | 10 | [lib] 11 | crate-type = ["cdylib", "rlib"] 12 | 13 | [dependencies] 14 | # async 15 | async-trait = "0.1" 16 | futures = "0.3" 17 | tower-lsp-server = { workspace = true } 18 | # web platform 19 | console_error_panic_hook = "0.1" 20 | js-sys = "0.3" 21 | wasm-bindgen = "0.2" 22 | wasm-bindgen-futures = { version = "0.4", features = [ 23 | "futures-core-03-stream", 24 | ] } 25 | wasm-streams = "0.2" 26 | # logging 27 | log = "0.4" 28 | console_log = "1" 29 | # fetch sources 30 | reqwest = { version = "0.12" } 31 | # workspace 32 | lsp-server = { path = "../../../lang/lsp" } 33 | driver = { path = "../../../lang/driver" } 34 | 35 | [dependencies.web-sys] 36 | version = "0.3" 37 | features = [ 38 | "console", 39 | "Window", 40 | "Location", 41 | "HtmlTextAreaElement", 42 | "ReadableStream", 43 | "WritableStream", 44 | ] 45 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "workspaces": [ 4 | "packages/app" 5 | ] 6 | } -------------------------------------------------------------------------------- /web/packages/app/.gitignore: -------------------------------------------------------------------------------- 1 | assets/wasm 2 | dist 3 | -------------------------------------------------------------------------------- /web/packages/app/.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /web/packages/app/assets/editor.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | body { 8 | height: 100vh; 9 | width: 100vw; 10 | } 11 | 12 | * { 13 | box-sizing: border-box; 14 | } 15 | 16 | div[class="editor"] { 17 | height: 100%; 18 | width: 100%; 19 | } 20 | -------------------------------------------------------------------------------- /web/packages/app/assets/editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Editor 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /web/packages/app/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.module.css"; 2 | 3 | declare module "*?raw" { 4 | const content: string; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /web/packages/app/src/@types/global.d.ts: -------------------------------------------------------------------------------- 1 | declare const DEBUG: boolean; 2 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/codec/bytes.ts: -------------------------------------------------------------------------------- 1 | import { encoder, decoder } from "../codec"; 2 | 3 | export default class Bytes { 4 | static encode(input: string): Uint8Array { 5 | return encoder.encode(input); 6 | } 7 | 8 | static decode(input: Uint8Array): string { 9 | return decoder.decode(input); 10 | } 11 | 12 | static append( 13 | constructor: { new (length: number): T }, 14 | ...arrays: T[] 15 | ) { 16 | let totalLength = 0; 17 | for (const arr of arrays) { 18 | totalLength += arr.length; 19 | } 20 | const result = new constructor(totalLength); 21 | let offset = 0; 22 | for (const arr of arrays) { 23 | result.set(arr, offset); 24 | offset += arr.length; 25 | } 26 | return result; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/codec/headers.ts: -------------------------------------------------------------------------------- 1 | export default class Headers { 2 | static add(message: string): string { 3 | return `Content-Length: ${message.length}\r\n\r\n${message}`; 4 | } 5 | 6 | static remove(delimited: string): string { 7 | return delimited.replace(/^Content-Length:\s*\d+\s*/, ""); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/index.ts: -------------------------------------------------------------------------------- 1 | import "../../assets/editor.css"; 2 | 3 | import App from "./app"; 4 | 5 | const app = new App(); 6 | app.run().catch(console.error); 7 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//" 4 | }, 5 | "brackets": [ 6 | ["(", ")"], 7 | ["{", "}"] 8 | ], 9 | "autoClosingPairs": [ 10 | ["(", ")"], 11 | ["{", "}"] 12 | ], 13 | "surroundingPairs": [ 14 | ["(", ")"], 15 | ["{", "}"] 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/pol.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", 3 | "name": "pol", 4 | "patterns": [ 5 | { "include": "#keywords" }, 6 | { "include": "#symbols" }, 7 | { "include": "#comments" }, 8 | { "include": "#strings" } 9 | ], 10 | "repository": { 11 | "keywords": { 12 | "patterns": [ 13 | { 14 | "name": "keyword.control", 15 | "match": "\\b(data|codata|let|def|codef|match|comatch|absurd|Type|implicit|use|infix)\\b" 16 | } 17 | ] 18 | }, 19 | "symbols": { 20 | "patterns": [ 21 | { 22 | "match": "(;|=>|,|:|\\.)", 23 | "name": "keyword.syntax" 24 | } 25 | ] 26 | }, 27 | "comments": { 28 | "patterns": [ 29 | { 30 | "match": "//.*$", 31 | "name": "comment.line.double-slash.syntax" 32 | } 33 | ] 34 | }, 35 | "strings": { 36 | "patterns": [ 37 | { 38 | "name": "string.quoted.double", 39 | "begin": "\"", 40 | "end": "\"", 41 | "patterns": [ 42 | { 43 | "name": "constant.character.escape", 44 | "match": "\\\\." 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | }, 51 | "scopeName": "source.pol" 52 | } 53 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/tracer.ts: -------------------------------------------------------------------------------- 1 | import * as proto from "vscode-languageserver-protocol"; 2 | 3 | export default class Tracer { 4 | static client(message: string): void { 5 | DEBUG && console.log(`client -> server: ${message}`); 6 | } 7 | 8 | static server(input: string | proto.Message): void { 9 | const message: string = typeof input === "string" ? input : JSON.stringify(input); 10 | DEBUG && console.log(`server -> client: ${message}`); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /web/packages/app/src/editor/workers.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from "monaco-languageclient/tools"; 2 | import { useWorkerFactory } from "monaco-editor-wrapper/workerFactory"; 3 | 4 | export const configureMonacoWorkers = (logger?: Logger) => { 5 | useWorkerFactory({ 6 | workerOverrides: { 7 | ignoreMapping: true, 8 | workerLoaders: { 9 | TextEditorWorker: () => 10 | new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url), { type: "module" }), 11 | TextMateWorker: () => 12 | new Worker(new URL("@codingame/monaco-vscode-textmate-service-override/worker", import.meta.url), { 13 | type: "module", 14 | }), 15 | }, 16 | }, 17 | logger, 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /web/packages/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "rootDir": "src" 6 | }, 7 | "exclude": [] 8 | } 9 | -------------------------------------------------------------------------------- /web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["DOM", "ES2022"], 5 | "module": "ES2022", 6 | "moduleResolution": "node", 7 | "newLine": "lf", 8 | "allowSyntheticDefaultImports": true, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "strict": true, 12 | "skipLibCheck": true 13 | }, 14 | "exclude": ["."], 15 | "ts-node": { 16 | "compilerOptions": { 17 | "module": "CommonJS" 18 | } 19 | } 20 | } 21 | --------------------------------------------------------------------------------