├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── crates ├── README.md ├── mltt-cli │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── main.rs │ │ └── repl.rs ├── mltt-concrete │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── pretty.rs ├── mltt-core │ ├── Cargo.toml │ └── src │ │ ├── domain.rs │ │ ├── lib.rs │ │ ├── literal.rs │ │ ├── meta.rs │ │ ├── nbe.rs │ │ ├── pretty.rs │ │ ├── prim.rs │ │ ├── syntax.rs │ │ ├── validate.rs │ │ └── var.rs ├── mltt-elaborate │ ├── Cargo.toml │ └── src │ │ ├── clause.rs │ │ ├── context.rs │ │ ├── lib.rs │ │ ├── literal.rs │ │ ├── nbe.rs │ │ └── unify.rs ├── mltt-parse │ ├── Cargo.toml │ ├── src │ │ ├── lexer.rs │ │ ├── lib.rs │ │ ├── parser.rs │ │ └── token.rs │ └── tests │ │ ├── lexer.rs │ │ └── parser.rs ├── mltt-span │ ├── Cargo.toml │ └── src │ │ ├── file.rs │ │ ├── index │ │ ├── byte.rs │ │ ├── column.rs │ │ ├── line.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ ├── location.rs │ │ └── span.rs └── mltt-test │ ├── Cargo.toml │ └── src │ ├── lib.rs │ └── support.rs ├── rustfmt.toml └── tests ├── elaborate ├── check-fail │ ├── literal-intro │ │ └── int │ │ │ ├── u16 │ │ │ ├── dec-overflow.term.mltt │ │ │ ├── dec-overflow.type.mltt │ │ │ ├── dec-underflow.term.mltt │ │ │ └── dec-underflow.type.mltt │ │ │ └── u8 │ │ │ ├── dec-overflow.term.mltt │ │ │ ├── dec-overflow.type.mltt │ │ │ ├── dec-underflow.term.mltt │ │ │ └── dec-underflow.type.mltt │ └── record-intro │ │ ├── superfluous-field.term.mltt │ │ ├── superfluous-field.type.mltt │ │ ├── unexpected-field.term.mltt │ │ └── unexpected-field.type.mltt ├── check-pass │ ├── case │ │ ├── default-bind.term.mltt │ │ ├── default-bind.type.mltt │ │ ├── default.term.mltt │ │ ├── default.type.mltt │ │ ├── overlapping.term.mltt │ │ ├── overlapping.type.mltt │ │ ├── simple.term.mltt │ │ └── simple.type.mltt │ ├── fun-intro │ │ ├── explicit.term.mltt │ │ ├── explicit.type.mltt │ │ ├── implicit.term.mltt │ │ ├── implicit.type.mltt │ │ ├── instance.term.mltt │ │ └── instance.type.mltt │ ├── if.term.mltt │ ├── if.type.mltt │ ├── literal-intro │ │ └── int │ │ │ ├── s16 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ ├── s32 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ ├── s64 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ ├── s8 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ ├── u16 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ ├── u32 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ ├── u64 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ └── oct-min.type.mltt │ │ │ └── u8 │ │ │ ├── bin-max.term.mltt │ │ │ ├── bin-max.type.mltt │ │ │ ├── bin-min.term.mltt │ │ │ ├── bin-min.type.mltt │ │ │ ├── dec-max.term.mltt │ │ │ ├── dec-max.type.mltt │ │ │ ├── dec-min.term.mltt │ │ │ ├── dec-min.type.mltt │ │ │ ├── hex-max.term.mltt │ │ │ ├── hex-max.type.mltt │ │ │ ├── hex-min.term.mltt │ │ │ ├── hex-min.type.mltt │ │ │ ├── oct-max.term.mltt │ │ │ ├── oct-max.type.mltt │ │ │ ├── oct-min.term.mltt │ │ │ ├── oct-min.type.mltt │ │ │ ├── samples.term.mltt │ │ │ └── samples.type.mltt │ ├── parens.term.mltt │ ├── parens.type.mltt │ ├── prim.term.mltt │ ├── prim.type.mltt │ └── record-intro │ │ ├── dependent-pair.term.mltt │ │ ├── dependent-pair.type.mltt │ │ ├── singleton.term.mltt │ │ ├── singleton.type.mltt │ │ ├── singleton1.term.mltt │ │ └── singleton1.type.mltt ├── synth-fail │ ├── fun-intro │ │ └── ambiguous.term.mltt │ ├── hole │ │ └── ambiguous.term.mltt │ ├── let │ │ ├── already-defined.term.mltt │ │ └── not-yet-declared.term.mltt │ ├── literal-intro │ │ ├── float │ │ │ └── ambiguous.term.mltt │ │ └── int │ │ │ └── ambiguous.term.mltt │ ├── prim │ │ ├── ambiguous.term.mltt │ │ └── unknown.term.mltt │ ├── record-elim │ │ └── field-not-found.term.mltt │ ├── record-intro │ │ └── ambiguous.term.mltt │ ├── universe │ │ └── overflow.term.mltt │ └── var │ │ └── unbound.term.mltt └── synth-pass │ ├── fun-elim │ ├── explicit.term.mltt │ ├── explicit.type.mltt │ ├── implicit-insert-meta.term.mltt │ ├── implicit-insert-meta.type.mltt │ ├── implicit.term.mltt │ ├── implicit.type.mltt │ ├── instance.term.mltt │ └── instance.type.mltt │ ├── fun-type-arrow │ ├── term-term.term.mltt │ ├── term-term.type.mltt │ ├── term-type.term.mltt │ ├── term-type.type.mltt │ ├── term-type1.term.mltt │ ├── term-type1.type.mltt │ ├── type-term.term.mltt │ ├── type-term.type.mltt │ ├── type-type.term.mltt │ ├── type-type.type.mltt │ ├── type1-term.term.mltt │ └── type1-term.type.mltt │ ├── fun-type │ ├── param-group-1.term.mltt │ ├── param-group-1.type.mltt │ ├── param-group-2.term.mltt │ └── param-group-2.type.mltt │ ├── let │ ├── complicated.term.mltt │ ├── complicated.type.mltt │ ├── declaration-definition.term.mltt │ ├── declaration-definition.type.mltt │ ├── definition.term.mltt │ ├── definition.type.mltt │ ├── forward-declarations.term.mltt │ └── forward-declarations.type.mltt │ ├── literal-intro │ ├── char │ │ ├── ascii.term.mltt │ │ ├── ascii.type.mltt │ │ ├── escape-ascii-lower-max.term.mltt │ │ ├── escape-ascii-lower-max.type.mltt │ │ ├── escape-ascii-upper-max.term.mltt │ │ ├── escape-ascii-upper-max.type.mltt │ │ ├── escape-simple-back-slash.term.mltt │ │ ├── escape-simple-back-slash.type.mltt │ │ ├── escape-simple-carriage-return.term.mltt │ │ ├── escape-simple-carriage-return.type.mltt │ │ ├── escape-simple-double-quote.term.mltt │ │ ├── escape-simple-double-quote.type.mltt │ │ ├── escape-simple-new-line.term.mltt │ │ ├── escape-simple-new-line.type.mltt │ │ ├── escape-simple-null.term.mltt │ │ ├── escape-simple-null.type.mltt │ │ ├── escape-simple-single-quote.term.mltt │ │ ├── escape-simple-single-quote.type.mltt │ │ ├── escape-simple-tab.term.mltt │ │ ├── escape-simple-tab.type.mltt │ │ ├── escape-unicode-lower-max.term.mltt │ │ ├── escape-unicode-lower-max.type.mltt │ │ ├── escape-unicode-upper-max.term.mltt │ │ └── escape-unicode-upper-max.type.mltt │ └── string │ │ ├── ascii.term.mltt │ │ ├── ascii.type.mltt │ │ ├── escape-ascii-lower-max.term.mltt │ │ ├── escape-ascii-lower-max.type.mltt │ │ ├── escape-ascii-upper-max.term.mltt │ │ ├── escape-ascii-upper-max.type.mltt │ │ ├── escape-simple-back-slash.term.mltt │ │ ├── escape-simple-back-slash.type.mltt │ │ ├── escape-simple-carriage-return.term.mltt │ │ ├── escape-simple-carriage-return.type.mltt │ │ ├── escape-simple-double-quote.term.mltt │ │ ├── escape-simple-double-quote.type.mltt │ │ ├── escape-simple-new-line.term.mltt │ │ ├── escape-simple-new-line.type.mltt │ │ ├── escape-simple-null.term.mltt │ │ ├── escape-simple-null.type.mltt │ │ ├── escape-simple-single-quote.term.mltt │ │ ├── escape-simple-single-quote.type.mltt │ │ ├── escape-simple-tab.term.mltt │ │ ├── escape-simple-tab.type.mltt │ │ ├── escape-unicode-lower-max.term.mltt │ │ ├── escape-unicode-lower-max.type.mltt │ │ ├── escape-unicode-upper-max.term.mltt │ │ ├── escape-unicode-upper-max.type.mltt │ │ ├── escapes.term.mltt │ │ └── escapes.type.mltt │ ├── parens.term.mltt │ ├── parens.type.mltt │ ├── record-elim │ ├── dependent-pair.term.mltt │ ├── dependent-pair.type.mltt │ ├── singleton.term.mltt │ └── singleton.type.mltt │ ├── record-intro │ ├── empty.term.mltt │ └── empty.type.mltt │ ├── record-type │ ├── dependent-pair.term.mltt │ ├── dependent-pair.type.mltt │ ├── empty.term.mltt │ ├── empty.type.mltt │ ├── singleton.term.mltt │ ├── singleton.type.mltt │ ├── singleton1.term.mltt │ └── singleton1.type.mltt │ ├── universe │ ├── type.term.mltt │ ├── type.type.mltt │ ├── type0.term.mltt │ ├── type0.type.mltt │ ├── type1.term.mltt │ └── type1.type.mltt │ └── var │ ├── bool.term.mltt │ ├── bool.type.mltt │ ├── char.term.mltt │ ├── char.type.mltt │ ├── f32.term.mltt │ ├── f32.type.mltt │ ├── f64.term.mltt │ ├── f64.type.mltt │ ├── false.term.mltt │ ├── false.type.mltt │ ├── s16.term.mltt │ ├── s16.type.mltt │ ├── s32.term.mltt │ ├── s32.type.mltt │ ├── s64.term.mltt │ ├── s64.type.mltt │ ├── s8.term.mltt │ ├── s8.type.mltt │ ├── string.term.mltt │ ├── string.type.mltt │ ├── true.term.mltt │ ├── true.type.mltt │ ├── u16.term.mltt │ ├── u16.type.mltt │ ├── u32.term.mltt │ ├── u32.type.mltt │ ├── u64.term.mltt │ ├── u64.type.mltt │ ├── u8.term.mltt │ └── u8.type.mltt └── samples ├── categories.mltt ├── combinators.mltt ├── connectives.mltt ├── cumulativity.mltt ├── empty.mltt ├── primitives.mltt └── records.mltt /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | 4 | repl-history 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "./crates/mltt-cli", 4 | "./crates/mltt-concrete", 5 | "./crates/mltt-core", 6 | "./crates/mltt-parse", 7 | "./crates/mltt-elaborate", 8 | "./crates/mltt-span", 9 | "./crates/mltt-test", 10 | ] 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Brendan Zabarauskas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-nbe-for-mltt 2 | 3 | This originally started as a Rust port of Danny Gratzer's implementation of 4 | [Normalization by Evaluation for Martin-Löf Type Theory][nbe-for-mltt], but it 5 | has a slightly different architecture and some additional language features. 6 | The algorithm for the insertion and unification of metavariables was partly 7 | taken from Andras Korvacs' [Minimal TT Exampls][minimal-tt-examples] and 8 | [smalltt][smalltt] (although gluing is not yet implemented here). 9 | It will probably become the basis for a new front-end for 10 | [Pikelet](https://github.com/pikelet-lang/pikelet). 11 | 12 | In traditional type checking and normalization that uses [DeBruijn indices][de-bruijn-indices], 13 | you are required to shift variable indices whenever you open up binders. This 14 | is extremely expensive, and rules out future optimizations, like [using 15 | visitors][visitors] to reduce the number of intermediate allocations as the AST 16 | is traversed. This implementation avoids these problems by using a "semantic 17 | type checking" algorithm that uses DeBruijn indices for the core syntax, and 18 | DeBruijn levels in the syntax of the semantic domain. 19 | 20 | | Syntax | Binding method | Example | 21 | |---------------|-----------------------------|---------------------------------| 22 | | Concrete | Nominal | `λz. (λy. y (λx. x)) (λx. z x)` | 23 | | Core | Nameless (DeBruijn Indices) | `λ . (λ . 0 (λ . 0)) (λ . 1 0)` | 24 | | Domain | Nameless (DeBruijn Levels) | `λ . (λ . 1 (λ . 2)) (λ . 0 1)` | 25 | 26 | [nbe-for-mltt]: https://github.com/jozefg/nbe-for-mltt 27 | [minimal-tt-examples]: https://github.com/AndrasKovacs/minimal-tt-examples 28 | [smalltt]: https://github.com/AndrasKovacs/smalltt 29 | [de-bruijn-indices]: https://en.wikipedia.org/wiki/De_Bruijn_index 30 | [visitors]: https://github.com/pikelet-lang/pikelet/issues/75 31 | 32 | ## TODO 33 | 34 | - [x] Convert data types to Rust 35 | - [x] Port NbE and bidirectional type checking 36 | - [x] Add a parser for the concrete syntax 37 | - [x] Desugaring of concrete syntax to core syntax 38 | - [x] Resugaring of core syntax to concrete syntax 39 | - [ ] Pretty printing 40 | - [x] Basic pretty printing 41 | - [x] Preserve pretty names through type checking and normalization 42 | - [ ] Unfold metavariables when pretty printing values 43 | - [ ] Attempt to avoid unfolding variables when pretty printing values 44 | - [x] Add a REPL 45 | - [x] Add span information to ASTs to improve diagnostics 46 | - [ ] Pattern matching elaboration 47 | - [x] Simple cases 48 | - [ ] Nested cases 49 | - [ ] Multiple scrutinees 50 | - [ ] Lambda case 51 | - [x] Dependent record types 52 | - [x] Primitive operations 53 | - [ ] Unification 54 | - [x] Basic unification 55 | - [x] Function eta rules 56 | - [x] Record eta rules 57 | - [ ] [Pruning](https://gitter.im/pikelet-lang/Lobby?at=5cd519e60f381d0a768e7811) 58 | - [ ] [Skolemization](https://gitter.im/pikelet-lang/Lobby?at=5cd129ca6a84d76ed85bbefd) 59 | - [x] Metavariable insertion 60 | - [ ] Integration tests 61 | - [ ] Parse (pass) 62 | - [ ] Parse (fail) 63 | - [x] Elaboration (pass) 64 | - [ ] Elaboration (fail) 65 | - [ ] Normalization tests 66 | - [x] Sample modules 67 | - [ ] Error recovery in: 68 | - [x] Lexer 69 | - [ ] Parser 70 | - [ ] Elaborator 71 | - [ ] Validator 72 | -------------------------------------------------------------------------------- /crates/README.md: -------------------------------------------------------------------------------- 1 | # The MLTT language implementation 2 | 3 | ## Crates 4 | 5 | | Name | Description | 6 | |-------------------------|-------------------------------------------------------------------| 7 | | [`mltt-cli`] | Command line interface | 8 | | [`mltt-parse`] | Lexing and parsing | 9 | | [`mltt-concrete`] | Concrete syntax | 10 | | [`mltt-elaborate`] | Elaboration from the concrete syntax to the core syntax | 11 | | [`mltt-core`] | Core syntax, NbE, and validation | 12 | | [`mltt-span`] | Data structures for tracking source positions | 13 | | [`mltt-test`] | Integration test harness | 14 | 15 | [`mltt-cli`]: /crates/mltt-cli 16 | [`mltt-parse`]: /crates/mltt-parse 17 | [`mltt-concrete`]: /crates/mltt-concrete 18 | [`mltt-elaborate`]: /crates/mltt-elaborate 19 | [`mltt-core`]: /crates/mltt-core 20 | [`mltt-span`]: /crates/mltt-span 21 | [`mltt-test`]: /crates/mltt-test 22 | -------------------------------------------------------------------------------- /crates/mltt-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-cli" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "The command line interface for the MLTT language" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | language-reporting = { git = "https://github.com/nikomatsakis/language-reporting", branch = "remove-codespan-dep" } 12 | mltt-concrete = { path = "../mltt-concrete"} 13 | mltt-core = { path = "../mltt-core"} 14 | mltt-elaborate = { path = "../mltt-elaborate"} 15 | mltt-parse = { path = "../mltt-parse"} 16 | mltt-span = { path = "../mltt-span"} 17 | pretty_env_logger = "0.3" 18 | rustyline = "4.1" 19 | structopt = "0.2" 20 | -------------------------------------------------------------------------------- /crates/mltt-cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The command line interface for the MLTT language. 2 | 3 | #![warn(rust_2018_idioms)] 4 | 5 | use std::error::Error; 6 | 7 | pub mod repl; 8 | 9 | /// The MLTT command line interface. 10 | #[derive(structopt::StructOpt)] 11 | #[structopt(name = "mltt")] 12 | pub enum Options { 13 | /// Type check some files. 14 | #[structopt(name = "check")] 15 | Check, 16 | /// Runs the language server/IDE support. 17 | #[structopt(name = "ide")] 18 | Ide, 19 | /// Runs the REPL/interactive mode. 20 | #[structopt(name = "repl")] 21 | Repl(repl::Options), 22 | } 23 | 24 | /// Run the CLI with the given options 25 | pub fn run(options: Options) -> Result<(), Box> { 26 | match options { 27 | Options::Check => Err("not yet implemented".into()), 28 | Options::Ide => Err("not yet implemented".into()), 29 | Options::Repl(options) => repl::run(options), 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /crates/mltt-cli/src/main.rs: -------------------------------------------------------------------------------- 1 | #![warn(rust_2018_idioms)] 2 | 3 | use mltt_cli::Options; 4 | use std::error::Error; 5 | use structopt::StructOpt; 6 | 7 | fn main() -> Result<(), Box> { 8 | pretty_env_logger::init(); 9 | 10 | mltt_cli::run(Options::from_args()) 11 | } 12 | -------------------------------------------------------------------------------- /crates/mltt-cli/src/repl.rs: -------------------------------------------------------------------------------- 1 | use language_reporting::termcolor::{ColorChoice, StandardStream}; 2 | use language_reporting::Diagnostic; 3 | use mltt_core::{domain, meta, pretty, syntax}; 4 | use mltt_elaborate::{Context, MetaInsertion}; 5 | use mltt_parse::lexer::Lexer; 6 | use mltt_parse::parser; 7 | use mltt_span::{File, FileSpan, Files}; 8 | use rustyline::error::ReadlineError; 9 | use rustyline::{Config, Editor}; 10 | use std::error::Error; 11 | use std::io::Write; 12 | use std::path::PathBuf; 13 | use std::rc::Rc; 14 | 15 | /// The MLTT REPL/interactive mode. 16 | #[derive(structopt::StructOpt)] 17 | pub struct Options { 18 | /// The file to save the command history to. 19 | #[structopt(long = "history-file", default_value = "repl-history")] 20 | pub history_file: PathBuf, 21 | /// The prompt to display before expressions. 22 | #[structopt(long = "prompt", default_value = "> ")] 23 | pub prompt: String, 24 | } 25 | 26 | /// Run the REPL with the given options. 27 | pub fn run(options: Options) -> Result<(), Box> { 28 | let mut writer = StandardStream::stdout(ColorChoice::Always); 29 | let mut editor = { 30 | let config = Config::builder() 31 | .history_ignore_space(true) 32 | .history_ignore_dups(true) 33 | .build(); 34 | 35 | Editor::<()>::with_config(config) 36 | }; 37 | 38 | if editor.load_history(&options.history_file).is_err() { 39 | // No previous REPL history! 40 | } 41 | 42 | let mut files = Files::new(); 43 | let context = Context::default(); 44 | let mut metas = meta::Env::new(); 45 | 46 | loop { 47 | match editor.readline(&options.prompt) { 48 | Ok(line) => { 49 | let file_id = files.add("repl", line); 50 | let file = &files[file_id]; 51 | editor.add_history_entry(file.contents()); 52 | 53 | match read_eval(&context, &mut metas, file) { 54 | Ok((term, ty)) => { 55 | let output = pretty::ann( 56 | context.term_to_doc(&term), 57 | context.value_to_doc(&metas, &ty), 58 | ); 59 | 60 | let width = pretty_width(&mut editor); 61 | writeln!(writer, "{}", output.pretty(width))?; 62 | }, 63 | Err(diagnostic) => { 64 | let config = language_reporting::DefaultConfig; 65 | language_reporting::emit(&mut writer.lock(), &files, &diagnostic, &config)?; 66 | }, 67 | } 68 | }, 69 | Err(ReadlineError::Interrupted) => println!("Interrupted!"), 70 | Err(ReadlineError::Eof) => break, 71 | Err(error) => return Err(error.into()), 72 | } 73 | } 74 | 75 | editor.save_history(&options.history_file)?; 76 | 77 | println!("Bye bye"); 78 | 79 | Ok(()) 80 | } 81 | 82 | /// Get the pretty width of the editor. 83 | fn pretty_width(editor: &mut Editor<()>) -> usize { 84 | match editor.dimensions() { 85 | Some((width, _)) => width, 86 | None => 1000_000_000, 87 | } 88 | } 89 | 90 | /// Read and evaluate the given file. 91 | fn read_eval( 92 | context: &Context, 93 | metas: &mut meta::Env, 94 | file: &File, 95 | ) -> Result<(Rc, Rc), Diagnostic> { 96 | let lexer = Lexer::new(&file); 97 | let concrete_term = parser::parse_term(lexer)?;; 98 | 99 | let (core_term, ty) = 100 | mltt_elaborate::synth_term(MetaInsertion::Yes, &context, metas, &concrete_term)?; 101 | 102 | let term_span = concrete_term.span(); 103 | let term = context.normalize_term(metas, term_span, &core_term)?; 104 | 105 | Ok((term, ty)) 106 | } 107 | -------------------------------------------------------------------------------- /crates/mltt-concrete/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-concrete" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "The concrete syntax of the MLTT language" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | im = "15.1.0" 12 | language-reporting = { git = "https://github.com/nikomatsakis/language-reporting", branch = "remove-codespan-dep" } 13 | log = "0.4" 14 | mltt-span = { path = "../mltt-span" } 15 | pretty = "0.5" 16 | -------------------------------------------------------------------------------- /crates/mltt-concrete/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The concrete syntax of the MLTT language. 2 | //! 3 | //! This could also be referred to as a 'parse tree'. We should aim to be able 4 | //! to reproduce the source code that the user typed in based on this syntax 5 | //! tree. 6 | //! 7 | //! In the future we might want to use a different representation that makes 8 | //! incremental updates faster. [Swift's parse tree] seems like an interesting 9 | //! approach to this problem, but comes with the downside of extra memory 10 | //! overhead and complexity. 11 | //! 12 | //! [Swift's parse tree]: https://github.com/apple/swift/tree/daf7d249a528ceea3c6b8ff8f5226be9af67f85c/lib/Syntax 13 | 14 | #![warn(rust_2018_idioms)] 15 | 16 | use mltt_span::{ByteIndex, ByteSize, FileId, FileSpan}; 17 | use std::borrow::Cow; 18 | use std::fmt; 19 | 20 | pub mod pretty; 21 | 22 | /// Top-level items in a module. 23 | #[derive(Debug, Clone, PartialEq)] 24 | pub enum Item<'file> { 25 | /// Forward-declarations. 26 | Declaration(Declaration<'file>), 27 | /// Term definitions. 28 | Definition(Definition<'file>), 29 | } 30 | 31 | impl<'file> Item<'file> { 32 | /// Returns `true` if the item is a definition. 33 | pub fn is_definition(&self) -> bool { 34 | match self { 35 | Item::Declaration(_) => false, 36 | Item::Definition(_) => true, 37 | } 38 | } 39 | 40 | pub fn span(&self) -> FileSpan { 41 | match self { 42 | Item::Declaration(declaration) => declaration.span(), 43 | Item::Definition(definition) => definition.span(), 44 | } 45 | } 46 | } 47 | 48 | /// Forward-declarations. 49 | #[derive(Debug, Clone, PartialEq)] 50 | pub struct Declaration<'file> { 51 | pub docs: Vec>, 52 | pub label: SpannedString<'file>, 53 | pub body_ty: Term<'file>, 54 | } 55 | 56 | impl<'file> Declaration<'file> { 57 | pub fn span(&self) -> FileSpan { 58 | FileSpan::merge(self.label.span(), self.body_ty.span()) 59 | } 60 | } 61 | 62 | /// Term definitions. 63 | #[derive(Debug, Clone, PartialEq)] 64 | pub struct Definition<'file> { 65 | pub docs: Vec>, 66 | pub label: SpannedString<'file>, 67 | pub params: Vec>, 68 | pub body_ty: Option>, 69 | pub body: Term<'file>, 70 | } 71 | 72 | impl<'file> Definition<'file> { 73 | pub fn span(&self) -> FileSpan { 74 | FileSpan::merge(self.label.span(), self.body.span()) 75 | } 76 | } 77 | 78 | #[derive(Copy, Clone, PartialEq, Eq)] 79 | pub struct SpannedString<'file> { 80 | pub source: FileId, 81 | pub start: ByteIndex, 82 | pub slice: &'file str, 83 | } 84 | 85 | impl<'file> SpannedString<'file> { 86 | pub fn new( 87 | source: FileId, 88 | start: impl Into, 89 | slice: &'file str, 90 | ) -> SpannedString<'file> { 91 | SpannedString { 92 | source, 93 | start: start.into(), 94 | slice, 95 | } 96 | } 97 | 98 | pub fn span(&self) -> FileSpan { 99 | FileSpan::new( 100 | self.source, 101 | self.start, 102 | self.start + ByteSize::from_str_len_utf8(&self.slice), 103 | ) 104 | } 105 | } 106 | 107 | impl<'file> fmt::Debug for SpannedString<'file> { 108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 109 | write!( 110 | f, 111 | "{span:?} {slice:?}", 112 | span = self.span(), 113 | slice = self.slice, 114 | ) 115 | } 116 | } 117 | 118 | impl<'file> fmt::Display for SpannedString<'file> { 119 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 120 | self.slice.fmt(f) 121 | } 122 | } 123 | 124 | impl<'file> Into for SpannedString<'file> { 125 | fn into(self) -> String { 126 | self.to_string() 127 | } 128 | } 129 | 130 | impl<'a, 'file> Into for &'a SpannedString<'file> { 131 | fn into(self) -> String { 132 | self.to_string() 133 | } 134 | } 135 | 136 | /// Concrete patterns. 137 | #[derive(Debug, Clone, PartialEq)] 138 | pub enum Pattern<'file> { 139 | /// Variable patterns. 140 | Var(SpannedString<'file>), 141 | /// Literal introductions. 142 | LiteralIntro(LiteralKind, SpannedString<'file>), 143 | // TODO: 144 | // /// Patterns with an explicit type annotation. 145 | // Ann(Box>, Box>), 146 | } 147 | 148 | impl<'file> Pattern<'file> { 149 | pub fn span(&self) -> FileSpan { 150 | match self { 151 | Pattern::Var(name) => name.span(), 152 | Pattern::LiteralIntro(_, literal) => literal.span(), 153 | } 154 | } 155 | } 156 | 157 | impl<'file> fmt::Display for Pattern<'file> { 158 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 159 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 160 | } 161 | } 162 | 163 | /// The kind of literal. 164 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 165 | pub enum LiteralKind { 166 | /// String literals. 167 | String, 168 | /// Char literals. 169 | Char, 170 | /// Integer literals. 171 | Int, 172 | /// Floating point literals. 173 | Float, 174 | } 175 | 176 | impl LiteralKind { 177 | /// Returns a string description of the literal kind. 178 | pub fn description(self) -> &'static str { 179 | match self { 180 | LiteralKind::String => "string", 181 | LiteralKind::Char => "character", 182 | LiteralKind::Int => "integer", 183 | LiteralKind::Float => "floating point", 184 | } 185 | } 186 | } 187 | 188 | /// A group of parameters to be used in a function type. 189 | #[derive(Debug, Clone, PartialEq)] 190 | pub enum TypeParam<'file> { 191 | Explicit(FileSpan, Vec>, Term<'file>), 192 | Implicit(FileSpan, Vec>, Option>), 193 | Instance(FileSpan, SpannedString<'file>, Term<'file>), 194 | } 195 | 196 | impl<'file> TypeParam<'file> { 197 | pub fn span(&self) -> FileSpan { 198 | match self { 199 | TypeParam::Explicit(span, _, _) 200 | | TypeParam::Implicit(span, _, _) 201 | | TypeParam::Instance(span, _, _) => *span, 202 | } 203 | } 204 | } 205 | 206 | impl<'file> fmt::Display for TypeParam<'file> { 207 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 208 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 209 | } 210 | } 211 | 212 | /// A parameter pattern to be used in a function introduction. 213 | #[derive(Debug, Clone, PartialEq)] 214 | pub enum IntroParam<'file> { 215 | Explicit(Pattern<'file>), 216 | Implicit(FileSpan, SpannedString<'file>, Option>), 217 | Instance(FileSpan, SpannedString<'file>, Option>), 218 | } 219 | 220 | impl<'file> IntroParam<'file> { 221 | pub fn span(&self) -> FileSpan { 222 | match self { 223 | IntroParam::Explicit(pattern) => pattern.span(), 224 | IntroParam::Implicit(span, _, _) | IntroParam::Instance(span, _, _) => *span, 225 | } 226 | } 227 | } 228 | 229 | impl<'file> fmt::Display for IntroParam<'file> { 230 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 231 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 232 | } 233 | } 234 | 235 | /// An argument passed to a function. 236 | #[derive(Debug, Clone, PartialEq)] 237 | pub enum Arg<'file> { 238 | Explicit(Term<'file>), 239 | Implicit(FileSpan, SpannedString<'file>, Option>), 240 | Instance(FileSpan, SpannedString<'file>, Option>), 241 | } 242 | 243 | impl<'file> Arg<'file> { 244 | pub fn span(&self) -> FileSpan { 245 | match self { 246 | Arg::Explicit(term) => term.span(), 247 | Arg::Implicit(span, _, _) | Arg::Instance(span, _, _) => *span, 248 | } 249 | } 250 | 251 | pub fn desugar_arg_term(&self) -> Cow<'_, Term<'file>> { 252 | match self { 253 | Arg::Explicit(term) => Cow::Borrowed(term), 254 | Arg::Implicit(_, label, term) | Arg::Instance(_, label, term) => match term { 255 | None => Cow::Owned(Term::Var(label.clone())), 256 | Some(term) => Cow::Borrowed(term), 257 | }, 258 | } 259 | } 260 | } 261 | 262 | impl<'file> fmt::Display for Arg<'file> { 263 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 264 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 265 | } 266 | } 267 | 268 | #[derive(Debug, Clone, PartialEq)] 269 | pub struct RecordTypeField<'file> { 270 | pub docs: Vec>, 271 | pub label: SpannedString<'file>, 272 | pub ann: Term<'file>, 273 | } 274 | 275 | impl<'file> fmt::Display for RecordTypeField<'file> { 276 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 277 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 278 | } 279 | } 280 | 281 | #[derive(Debug, Clone, PartialEq)] 282 | pub enum RecordIntroField<'file> { 283 | Punned { 284 | label: SpannedString<'file>, 285 | }, 286 | Explicit { 287 | label: SpannedString<'file>, 288 | params: Vec>, 289 | body_ty: Option>, 290 | body: Term<'file>, 291 | }, 292 | } 293 | 294 | impl<'file> RecordIntroField<'file> { 295 | /// Desugar punned fields. 296 | pub fn desugar( 297 | &self, 298 | ) -> ( 299 | &SpannedString<'file>, 300 | &[IntroParam<'file>], 301 | std::option::Option<&Term<'file>>, 302 | std::borrow::Cow<'_, Term<'file>>, 303 | ) { 304 | match self { 305 | RecordIntroField::Punned { label } => { 306 | (label, &[][..], None, Cow::Owned(Term::Var(label.clone()))) 307 | }, 308 | RecordIntroField::Explicit { 309 | label, 310 | params, 311 | body_ty, 312 | body, 313 | } => (label, ¶ms[..], body_ty.as_ref(), Cow::Borrowed(body)), 314 | } 315 | } 316 | 317 | pub fn span(&self) -> FileSpan { 318 | match self { 319 | RecordIntroField::Punned { label } => label.span(), 320 | RecordIntroField::Explicit { label, body, .. } => { 321 | FileSpan::merge(label.span(), body.span()) 322 | }, 323 | } 324 | } 325 | } 326 | 327 | impl<'file> fmt::Display for RecordIntroField<'file> { 328 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 329 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 330 | } 331 | } 332 | 333 | /// Concrete terms. 334 | #[derive(Debug, Clone, PartialEq)] 335 | pub enum Term<'file> { 336 | /// Variables 337 | Var(SpannedString<'file>), 338 | /// Primitives 339 | Prim(FileSpan, SpannedString<'file>), 340 | /// Holes 341 | Hole(FileSpan), 342 | 343 | /// A parenthesized term 344 | Parens(FileSpan, Box>), 345 | /// A term that is explicitly annotated with a type 346 | Ann(Box>, Box>), 347 | /// Let bindings 348 | Let(FileSpan, Vec>, Box>), 349 | /// If expressions 350 | If( 351 | FileSpan, 352 | Box>, 353 | Box>, 354 | Box>, 355 | ), 356 | /// Case expressions 357 | Case( 358 | FileSpan, 359 | Box>, 360 | Vec<(Pattern<'file>, Term<'file>)>, 361 | ), 362 | 363 | /// Literal introductions. 364 | LiteralIntro(LiteralKind, SpannedString<'file>), 365 | 366 | /// Dependent function type 367 | /// 368 | /// Also known as a _pi type_ or _dependent product type_. 369 | FunType(FileSpan, Vec>, Box>), 370 | /// Non-dependent function types 371 | FunArrowType(Box>, Box>), 372 | /// Introduce a function 373 | /// 374 | /// Also known as a _lambda expression_ or _anonymous function_. 375 | FunIntro(FileSpan, Vec>, Box>), 376 | /// Eliminate a function by applying it to an argument 377 | FunElim(Box>, Vec>), 378 | 379 | /// Dependent record type 380 | RecordType(FileSpan, Vec>), 381 | /// Record introduction 382 | RecordIntro(FileSpan, Vec>), 383 | /// Eliminate a record by projecting on it 384 | RecordElim(Box>, SpannedString<'file>), 385 | 386 | /// Universe of types 387 | Universe(FileSpan, Option>), 388 | } 389 | 390 | impl<'file> Term<'file> { 391 | pub fn span(&self) -> FileSpan { 392 | match self { 393 | Term::Var(name) => name.span(), 394 | Term::Prim(span, _) => *span, 395 | Term::Hole(span) => *span, 396 | Term::Parens(span, _) => *span, 397 | Term::Ann(term, term_ty) => FileSpan::merge(term.span(), term_ty.span()), 398 | Term::Let(span, _, _) => *span, 399 | Term::If(span, _, _, _) => *span, 400 | Term::Case(span, _, _) => *span, 401 | Term::LiteralIntro(_, literal) => literal.span(), 402 | Term::FunType(span, _, _) => *span, 403 | Term::FunArrowType(param_ty, body_ty) => { 404 | FileSpan::merge(param_ty.span(), body_ty.span()) 405 | }, 406 | Term::FunIntro(span, _, _) => *span, 407 | Term::FunElim(fun, args) => { 408 | let mut span = fun.span(); 409 | if let Some(last_arg) = args.last() { 410 | span = FileSpan::merge(span, last_arg.span()); 411 | } 412 | span 413 | }, 414 | Term::RecordType(span, _) => *span, 415 | Term::RecordIntro(span, _) => *span, 416 | Term::RecordElim(record, label) => FileSpan::merge(record.span(), label.span()), 417 | Term::Universe(span, _) => *span, 418 | } 419 | } 420 | } 421 | 422 | impl<'file> fmt::Display for Term<'file> { 423 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 424 | self.to_doc().group().pretty(1_000_000_000).fmt(f) 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /crates/mltt-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-core" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "The core type theory of the MLTT language" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | im = "15.1.0" 12 | itertools = "0.8" 13 | log = "0.4" 14 | mltt-span = { path = "../mltt-span" } 15 | pretty = "0.5" 16 | -------------------------------------------------------------------------------- /crates/mltt-core/src/domain.rs: -------------------------------------------------------------------------------- 1 | //! The semantic domain. 2 | 3 | use std::rc::Rc; 4 | 5 | use super::literal::{LiteralIntro, LiteralType}; 6 | use crate::syntax::Term; 7 | use crate::{meta, prim, var, AppMode, DocString, Label, UniverseLevel}; 8 | 9 | /// Terms that are in _weak head normal form_. 10 | /// 11 | /// These can either be _neutral values_ (values that are stuck on a variable), 12 | /// or _canonical values_. 13 | #[derive(Debug, Clone, PartialEq)] 14 | pub enum Value { 15 | /// Neutral values 16 | /// 17 | /// Terms for which computation has stopped because of an attempt to 18 | /// evaluate a variable. 19 | /// 20 | /// These are known as _neutral values_ or _accumulators_. 21 | Neutral(Head, Spine), 22 | 23 | /// Literal types 24 | LiteralType(LiteralType), 25 | /// Literal introductions 26 | LiteralIntro(LiteralIntro), 27 | 28 | /// Dependent function types 29 | FunType(AppMode, Option, Rc, AppClosure), 30 | /// Introduce a function 31 | FunIntro(AppMode, Option, AppClosure), 32 | 33 | /// Dependent record type extension 34 | RecordTypeExtend(DocString, Label, Option, Rc, AppClosure), 35 | /// Empty record type 36 | RecordTypeEmpty, 37 | /// Introduce a record 38 | RecordIntro(Vec<(Label, Rc)>), 39 | 40 | /// Universe of types 41 | Universe(UniverseLevel), 42 | } 43 | 44 | impl Value { 45 | /// Construct a variable. 46 | pub fn var(level: impl Into) -> Value { 47 | Value::Neutral(Head::Var(level.into()), Vec::new()) 48 | } 49 | 50 | /// Construct a metavariable. 51 | pub fn meta(index: impl Into) -> Value { 52 | Value::Neutral(Head::Meta(index.into()), Vec::new()) 53 | } 54 | 55 | /// Construct a primitive. 56 | pub fn prim(name: impl Into) -> Value { 57 | Value::Neutral(Head::Prim(name.into()), Vec::new()) 58 | } 59 | 60 | /// Construct a literal type. 61 | pub fn literal_ty(ty: LiteralType) -> Value { 62 | Value::LiteralType(ty) 63 | } 64 | 65 | /// Construct a literal introduction. 66 | pub fn literal_intro(value: impl Into) -> Value { 67 | Value::LiteralIntro(value.into()) 68 | } 69 | 70 | /// Construct a universe. 71 | pub fn universe(level: impl Into) -> Value { 72 | Value::Universe(level.into()) 73 | } 74 | } 75 | 76 | /// Alias for types - we are using describing a dependently typed language 77 | /// types, so this is just an alias. 78 | pub type Type = Value; 79 | 80 | /// The head of a neutral term. 81 | #[derive(Debug, Clone, PartialEq)] 82 | pub enum Head { 83 | /// Variables 84 | Var(var::Level), 85 | /// Metavariables 86 | Meta(meta::Index), 87 | /// Primitives 88 | Prim(prim::Name), 89 | } 90 | 91 | /// A spine of eliminators. 92 | pub type Spine = Vec; 93 | 94 | /// An eliminator. 95 | #[derive(Debug, Clone, PartialEq)] 96 | pub enum Elim { 97 | /// Literal elimination (case split). 98 | Literal(LiteralClosure), 99 | /// Function elimination (application). 100 | Fun(AppMode, Rc), 101 | /// Record elimination (projection). 102 | Record(Label), 103 | } 104 | 105 | /// A closure that binds a single variable. 106 | /// 107 | /// We can think of these closures as a limited form of [_explicit substitutions_]. 108 | /// They allow us to avoid eagerly substituting under binders when evaluating 109 | /// terms. 110 | /// 111 | /// [_explicit substitutions_]: https://en.wikipedia.org/wiki/Explicit_substitution 112 | #[derive(Debug, Clone, PartialEq)] 113 | pub struct AppClosure { 114 | /// The term that the argument will be applied to. 115 | pub term: Rc, 116 | /// The environment in which we'll run the term in. 117 | /// 118 | /// At the moment this captures the _entire_ environment - would it be 119 | /// better to only capture what the `term` needs? 120 | pub values: var::Env>, 121 | } 122 | 123 | impl AppClosure { 124 | pub fn new(term: Rc, values: var::Env>) -> AppClosure { 125 | AppClosure { term, values } 126 | } 127 | } 128 | 129 | /// A closure that stores a list of clauses. 130 | #[derive(Debug, Clone, PartialEq)] 131 | pub struct LiteralClosure { 132 | /// The clauses. 133 | pub clauses: Rc<[(LiteralIntro, Rc)]>, 134 | /// The default term. 135 | pub default: Rc, 136 | /// The environment in which we'll run the clauses in. 137 | /// 138 | /// At the moment this captures the _entire_ environment - would it be 139 | /// better to only capture what the `term` needs? 140 | pub values: var::Env>, 141 | } 142 | 143 | impl LiteralClosure { 144 | pub fn new( 145 | clauses: Rc<[(LiteralIntro, Rc)]>, 146 | default: Rc, 147 | values: var::Env>, 148 | ) -> LiteralClosure { 149 | LiteralClosure { 150 | clauses, 151 | default, 152 | values, 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /crates/mltt-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The core type theory of the MLTT language. 2 | 3 | #![warn(rust_2018_idioms)] 4 | 5 | use std::fmt; 6 | use std::rc::Rc; 7 | use std::u16; 8 | 9 | pub mod meta; 10 | pub mod var; 11 | 12 | pub mod domain; 13 | pub mod literal; 14 | pub mod pretty; 15 | pub mod prim; 16 | pub mod syntax; 17 | 18 | pub mod nbe; 19 | pub mod validate; 20 | 21 | /// Reference counted documentation string. 22 | pub type DocString = Rc; 23 | 24 | /// A label. These are treated as significant when comparing terms for alpha 25 | /// equivalence. 26 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 27 | pub struct Label(pub String); 28 | 29 | impl fmt::Display for Label { 30 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 31 | self.0.fmt(f) 32 | } 33 | } 34 | 35 | /// The application mode of a function. 36 | #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 37 | pub enum AppMode { 38 | /// Explicit application mode. 39 | Explicit, 40 | /// Implicit application mode. 41 | Implicit(Label), 42 | /// Instance application mode. 43 | Instance(Label), 44 | } 45 | 46 | impl fmt::Display for AppMode { 47 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 48 | match self { 49 | AppMode::Explicit => write!(f, "_"), 50 | AppMode::Implicit(label) => write!(f, "{{{}}}", label), 51 | AppMode::Instance(label) => write!(f, "{{{{{}}}}}", label), 52 | } 53 | } 54 | } 55 | 56 | /// The level of a universe. 57 | /// 58 | /// We allow room for `65535` levels, which should be more than enough for most 59 | /// sane purposes! 60 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 61 | pub struct UniverseLevel(pub u16); 62 | 63 | impl UniverseLevel { 64 | /// The maximum universe level that can be represented. 65 | pub const MAX: UniverseLevel = UniverseLevel(u16::MAX); 66 | 67 | /// Shift the by the given amount, returning an error if maximum universe 68 | /// level has been reached. 69 | pub fn shift(self, shift: u16) -> Option { 70 | Some(UniverseLevel(self.0.checked_add(shift)?)) 71 | } 72 | } 73 | 74 | impl From for UniverseLevel { 75 | fn from(src: u16) -> UniverseLevel { 76 | UniverseLevel(src) 77 | } 78 | } 79 | 80 | impl fmt::Display for UniverseLevel { 81 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 82 | self.0.fmt(f) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /crates/mltt-core/src/literal.rs: -------------------------------------------------------------------------------- 1 | //! Core literals. 2 | 3 | use std::fmt; 4 | use std::rc::Rc; 5 | 6 | /// Literal types. 7 | #[derive(Debug, Clone, PartialEq, PartialOrd)] 8 | pub enum LiteralType { 9 | String, 10 | Char, 11 | Bool, 12 | U8, 13 | U16, 14 | U32, 15 | U64, 16 | S8, 17 | S16, 18 | S32, 19 | S64, 20 | F32, 21 | F64, 22 | } 23 | 24 | impl LiteralType { 25 | pub fn alpha_eq(&self, other: &LiteralType) -> bool { 26 | self == other 27 | } 28 | } 29 | 30 | impl fmt::Display for LiteralType { 31 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 32 | match self { 33 | LiteralType::String => write!(f, "String"), 34 | LiteralType::Char => write!(f, "Char"), 35 | LiteralType::Bool => write!(f, "Bool"), 36 | LiteralType::U8 => write!(f, "U8"), 37 | LiteralType::U16 => write!(f, "U16"), 38 | LiteralType::U32 => write!(f, "U32"), 39 | LiteralType::U64 => write!(f, "U64"), 40 | LiteralType::S8 => write!(f, "S8"), 41 | LiteralType::S16 => write!(f, "S16"), 42 | LiteralType::S32 => write!(f, "S32"), 43 | LiteralType::S64 => write!(f, "S64"), 44 | LiteralType::F32 => write!(f, "F32"), 45 | LiteralType::F64 => write!(f, "F64"), 46 | } 47 | } 48 | } 49 | 50 | /// Literal introductions. 51 | #[derive(Debug, Clone, PartialEq, PartialOrd)] 52 | pub enum LiteralIntro { 53 | String(Rc), 54 | Char(char), 55 | Bool(bool), 56 | U8(u8), 57 | U16(u16), 58 | U32(u32), 59 | U64(u64), 60 | S8(i8), 61 | S16(i16), 62 | S32(i32), 63 | S64(i64), 64 | F32(f32), 65 | F64(f64), 66 | } 67 | 68 | impl LiteralIntro { 69 | pub fn alpha_eq(&self, other: &LiteralIntro) -> bool { 70 | match (self, other) { 71 | (LiteralIntro::String(v1), LiteralIntro::String(v2)) => v1 == v2, 72 | (LiteralIntro::Char(v1), LiteralIntro::Char(v2)) => v1 == v2, 73 | (LiteralIntro::Bool(v1), LiteralIntro::Bool(v2)) => v1 == v2, 74 | (LiteralIntro::U8(v1), LiteralIntro::U8(v2)) => v1 == v2, 75 | (LiteralIntro::U16(v1), LiteralIntro::U16(v2)) => v1 == v2, 76 | (LiteralIntro::U32(v1), LiteralIntro::U32(v2)) => v1 == v2, 77 | (LiteralIntro::U64(v1), LiteralIntro::U64(v2)) => v1 == v2, 78 | (LiteralIntro::S8(v1), LiteralIntro::S8(v2)) => v1 == v2, 79 | (LiteralIntro::S16(v1), LiteralIntro::S16(v2)) => v1 == v2, 80 | (LiteralIntro::S32(v1), LiteralIntro::S32(v2)) => v1 == v2, 81 | (LiteralIntro::S64(v1), LiteralIntro::S64(v2)) => v1 == v2, 82 | // Use bitwise equality, combined with a NaN check to provide a 83 | // logically consistent equality comparison of floating point 84 | // numbers. This means that the following weirdness (from an 85 | // IEEE-754 perspective) happens at the type level: 86 | // 87 | // - 0.0 != -0.0 88 | // - NaN == NaN 89 | // - NaN == -NaN 90 | // 91 | // # References 92 | // 93 | // - https://github.com/idris-lang/Idris-dev/issues/2609 94 | // - https://github.com/dhall-lang/dhall-lang/issues/425 95 | // - https://github.com/agda/agda/issues/2169 96 | // - https://agda.readthedocs.io/en/v2.5.4.2/language/built-ins.html#floats 97 | (LiteralIntro::F32(v1), LiteralIntro::F32(v2)) => { 98 | v1.to_bits() == v2.to_bits() || v1.is_nan() && v2.is_nan() 99 | }, 100 | (LiteralIntro::F64(v1), LiteralIntro::F64(v2)) => { 101 | v1.to_bits() == v2.to_bits() || v1.is_nan() && v2.is_nan() 102 | }, 103 | (_, _) => false, 104 | } 105 | } 106 | } 107 | 108 | impl fmt::Display for LiteralIntro { 109 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 110 | match self { 111 | LiteralIntro::String(value) => write!(f, "{:?}", value), 112 | LiteralIntro::Char(value) => write!(f, "{:?}", value), 113 | LiteralIntro::Bool(true) => write!(f, "true"), 114 | LiteralIntro::Bool(false) => write!(f, "false"), 115 | LiteralIntro::U8(value) => write!(f, "{}", value), 116 | LiteralIntro::U16(value) => write!(f, "{}", value), 117 | LiteralIntro::U32(value) => write!(f, "{}", value), 118 | LiteralIntro::U64(value) => write!(f, "{}", value), 119 | LiteralIntro::S8(value) => write!(f, "{}", value), 120 | LiteralIntro::S16(value) => write!(f, "{}", value), 121 | LiteralIntro::S32(value) => write!(f, "{}", value), 122 | LiteralIntro::S64(value) => write!(f, "{}", value), 123 | LiteralIntro::F32(value) => write!(f, "{}", value), 124 | LiteralIntro::F64(value) => write!(f, "{}", value), 125 | } 126 | } 127 | } 128 | 129 | macro_rules! impl_from_to_literal_intro { 130 | ($T:ty, $Literal:ident) => { 131 | impl From<$T> for LiteralIntro { 132 | fn from(src: $T) -> LiteralIntro { 133 | LiteralIntro::$Literal(src) 134 | } 135 | } 136 | }; 137 | } 138 | 139 | impl_from_to_literal_intro!(Rc, String); 140 | impl_from_to_literal_intro!(char, Char); 141 | impl_from_to_literal_intro!(bool, Bool); 142 | impl_from_to_literal_intro!(u8, U8); 143 | impl_from_to_literal_intro!(u16, U16); 144 | impl_from_to_literal_intro!(u32, U32); 145 | impl_from_to_literal_intro!(u64, U64); 146 | impl_from_to_literal_intro!(i8, S8); 147 | impl_from_to_literal_intro!(i16, S16); 148 | impl_from_to_literal_intro!(i32, S32); 149 | impl_from_to_literal_intro!(i64, S64); 150 | impl_from_to_literal_intro!(f32, F32); 151 | impl_from_to_literal_intro!(f64, F64); 152 | 153 | impl<'a> From<&'a str> for LiteralIntro { 154 | fn from(src: &'a str) -> LiteralIntro { 155 | LiteralIntro::String(Rc::from(src)) 156 | } 157 | } 158 | 159 | impl From for LiteralIntro { 160 | fn from(src: String) -> LiteralIntro { 161 | LiteralIntro::String(Rc::from(src)) 162 | } 163 | } 164 | 165 | #[cfg(test)] 166 | mod tests { 167 | use std::{f32, f64}; 168 | 169 | use super::*; 170 | 171 | use self::LiteralIntro::{F32, F64}; 172 | 173 | #[test] 174 | fn alpha_eq_f32_nan_nan() { 175 | assert!(LiteralIntro::alpha_eq(&F32(f32::NAN), &F32(f32::NAN))); 176 | } 177 | 178 | #[test] 179 | fn alpha_eq_f32_neg_nan_nan() { 180 | assert!(LiteralIntro::alpha_eq(&F32(-f32::NAN), &F32(f32::NAN))); 181 | } 182 | 183 | #[test] 184 | fn alpha_eq_f32_nan_neg_nan() { 185 | assert!(LiteralIntro::alpha_eq(&F32(f32::NAN), &F32(-f32::NAN))); 186 | } 187 | 188 | #[test] 189 | fn alpha_eq_f32_neg_nan_neg_nan() { 190 | assert!(LiteralIntro::alpha_eq(&F32(-f32::NAN), &F32(-f32::NAN))); 191 | } 192 | 193 | #[test] 194 | fn alpha_eq_f32_zero_zero() { 195 | assert!(LiteralIntro::alpha_eq(&F32(0.0), &F32(0.0))); 196 | } 197 | 198 | #[test] 199 | fn alpha_eq_f32_neg_zero_zero() { 200 | assert!(!LiteralIntro::alpha_eq(&F32(-0.0), &F32(0.0))); 201 | } 202 | 203 | #[test] 204 | fn alpha_eq_f32_zero_neg_zero() { 205 | assert!(!LiteralIntro::alpha_eq(&F32(0.0), &F32(-0.0))); 206 | } 207 | 208 | #[test] 209 | fn alpha_eq_f32_neg_zero_neg_zero() { 210 | assert!(LiteralIntro::alpha_eq(&F32(-0.0), &F32(-0.0))); 211 | } 212 | 213 | #[test] 214 | fn alpha_eq_f64_nan_nan() { 215 | assert!(LiteralIntro::alpha_eq(&F64(f64::NAN), &F64(f64::NAN))); 216 | } 217 | 218 | #[test] 219 | fn alpha_eq_f64_neg_nan_nan() { 220 | assert!(LiteralIntro::alpha_eq(&F64(-f64::NAN), &F64(f64::NAN))); 221 | } 222 | 223 | #[test] 224 | fn alpha_eq_f64_nan_neg_nan() { 225 | assert!(LiteralIntro::alpha_eq(&F64(f64::NAN), &F64(-f64::NAN))); 226 | } 227 | 228 | #[test] 229 | fn alpha_eq_f64_neg_nan_neg_nan() { 230 | assert!(LiteralIntro::alpha_eq(&F64(-f64::NAN), &F64(-f64::NAN))); 231 | } 232 | 233 | #[test] 234 | fn alpha_eq_f64_zero_zero() { 235 | assert!(LiteralIntro::alpha_eq(&F64(0.0), &F64(0.0))); 236 | } 237 | 238 | #[test] 239 | fn alpha_eq_f64_neg_zero_zero() { 240 | assert!(!LiteralIntro::alpha_eq(&F64(-0.0), &F64(0.0))); 241 | } 242 | 243 | #[test] 244 | fn alpha_eq_f64_zero_neg_zero() { 245 | assert!(!LiteralIntro::alpha_eq(&F64(0.0), &F64(-0.0))); 246 | } 247 | 248 | #[test] 249 | fn alpha_eq_f64_neg_zero_neg_zero() { 250 | assert!(LiteralIntro::alpha_eq(&F64(-0.0), &F64(-0.0))); 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /crates/mltt-core/src/meta.rs: -------------------------------------------------------------------------------- 1 | use mltt_span::FileSpan; 2 | use std::fmt; 3 | use std::rc::Rc; 4 | 5 | use crate::domain; 6 | 7 | /// Metavariable index. 8 | /// 9 | /// These are used as placeholders for undetermined terms that we will need to 10 | /// eventually fill in during elaboration. They can also be used to stand for 11 | /// 'holes' in the concrete syntax, to support type-directed editing. 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 13 | pub struct Index(pub u32); 14 | 15 | impl std::fmt::Display for Index { 16 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 17 | write!(f, "?{}", self.0) 18 | } 19 | } 20 | 21 | impl From for Index { 22 | fn from(src: u32) -> Index { 23 | Index(src) 24 | } 25 | } 26 | 27 | /// An entry in the metavariable environment. 28 | #[derive(Debug, Clone, PartialEq)] 29 | pub enum Solution { 30 | Unsolved, 31 | Solved(Rc), 32 | } 33 | 34 | /// An environment of solved and unsolved metavariables. 35 | #[derive(Debug, Clone, PartialEq)] 36 | pub struct Env { 37 | /// The solutions. 38 | solutions: Vec<(FileSpan, Solution, Rc)>, 39 | } 40 | 41 | impl Env { 42 | /// Create a new, empty environment. 43 | pub fn new() -> Env { 44 | Env { 45 | solutions: Vec::new(), 46 | } 47 | } 48 | 49 | /// Lookup a the solution for a metavariable in the environment. 50 | pub fn lookup_solution(&self, index: Index) -> Option<&(FileSpan, Solution, Rc)> { 51 | self.solutions.get(index.0 as usize) 52 | } 53 | 54 | /// Add a solution to the given metavariable index. 55 | pub fn add_solved(&mut self, index: Index, solved: Rc) { 56 | match self.solutions.get_mut(index.0 as usize) { 57 | Some((_, solution @ Solution::Unsolved, _)) => *solution = Solution::Solved(solved), 58 | Some((_, Solution::Solved(_), _)) => unimplemented!("updating solved solution"), 59 | None => unimplemented!("no corresponding solution"), 60 | } 61 | } 62 | 63 | /// Create a fresh metavariable index. 64 | pub fn add_unsolved(&mut self, span: FileSpan, ty: Rc) -> Index { 65 | let index = Index(self.solutions.len() as u32); 66 | self.solutions.push((span, Solution::Unsolved, ty)); 67 | index 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /crates/mltt-core/src/syntax.rs: -------------------------------------------------------------------------------- 1 | //! The core syntax of the language. 2 | 3 | use std::fmt; 4 | use std::rc::Rc; 5 | 6 | use super::literal::{LiteralIntro, LiteralType}; 7 | use crate::{meta, prim, var, AppMode, DocString, Label, UniverseLevel}; 8 | 9 | /// Top-level module. 10 | #[derive(Clone, PartialEq)] 11 | pub struct Module { 12 | pub items: Vec, 13 | } 14 | 15 | impl fmt::Debug for Module { 16 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 17 | let doc = self.to_debug_doc().group(); 18 | fmt::Display::fmt(&doc.pretty(1_000_000_000), f) 19 | } 20 | } 21 | 22 | /// Top-level item. 23 | #[derive(Clone, PartialEq)] 24 | pub enum Item { 25 | /// Forward-declarations. 26 | Declaration(DocString, Label, Rc), 27 | /// Term definitions. 28 | Definition(DocString, Label, Rc), 29 | } 30 | 31 | impl fmt::Debug for Item { 32 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 33 | let doc = self.to_debug_doc().group(); 34 | fmt::Display::fmt(&doc.pretty(1_000_000_000), f) 35 | } 36 | } 37 | 38 | /// Core terms. 39 | // TODO: explicitly annotate with types 40 | #[derive(Clone, PartialEq)] 41 | pub enum Term { 42 | /// Variables 43 | Var(var::Index), 44 | /// Metavariables 45 | Meta(meta::Index), 46 | /// Primitives 47 | Prim(prim::Name), 48 | 49 | /// A term that is explicitly annotated with a type 50 | Ann(Rc, Rc), 51 | /// Let bindings 52 | Let(Vec, Rc), 53 | 54 | /// Literal types 55 | LiteralType(LiteralType), 56 | /// Literal introductions 57 | LiteralIntro(LiteralIntro), 58 | /// Eliminate a literal (case split on literals) 59 | /// 60 | /// We include a scrutinee, a list of clauses, and a default term. The 61 | /// clauses are sorted in ascending order by the literal to allow for 62 | /// efficient binary searching during evaluation. 63 | LiteralElim(Rc, Rc<[(LiteralIntro, Rc)]>, Rc), 64 | 65 | /// Dependent function types 66 | FunType(AppMode, Option, Rc, Rc), 67 | /// Introduce a function 68 | FunIntro(AppMode, Option, Rc), 69 | /// Eliminate a function (application) 70 | FunElim(Rc, AppMode, Rc), 71 | 72 | /// Dependent record types 73 | RecordType(Vec<(DocString, Label, Option, Rc)>), 74 | /// Introduce a record 75 | RecordIntro(Vec<(Label, Rc)>), 76 | /// Eliminate a record (projection) 77 | RecordElim(Rc, Label), 78 | 79 | /// Universe of types 80 | Universe(UniverseLevel), 81 | } 82 | 83 | impl Term { 84 | /// Construct a variable. 85 | pub fn var(index: impl Into) -> Term { 86 | Term::Var(index.into()) 87 | } 88 | 89 | /// Construct a metavariable. 90 | pub fn meta(index: impl Into) -> Term { 91 | Term::Meta(index.into()) 92 | } 93 | 94 | /// Construct a primitive. 95 | pub fn prim(name: impl Into) -> Term { 96 | Term::Prim(name.into()) 97 | } 98 | 99 | /// Construct an annotated term. 100 | pub fn ann(term: impl Into>, term_ty: impl Into>) -> Term { 101 | Term::Ann(term.into(), term_ty.into()) 102 | } 103 | 104 | /// Construct a literal type. 105 | pub fn literal_ty(ty: impl Into) -> Term { 106 | Term::LiteralType(ty.into()) 107 | } 108 | 109 | /// Construct a literal introduction. 110 | pub fn literal_intro(value: impl Into) -> Term { 111 | Term::LiteralIntro(value.into()) 112 | } 113 | 114 | /// Construct a universe. 115 | pub fn universe(level: impl Into) -> Term { 116 | Term::Universe(level.into()) 117 | } 118 | 119 | /// Checks if a term is _alpha equivalent_ to another term. 120 | /// 121 | /// This means that the two terms share the same binding structure, while 122 | /// disregarding the actual names used for those binders. For example, we 123 | /// consider the following terms to be alpha equivalent: 124 | /// 125 | /// - `fun x => x` and `fun y => y` 126 | /// - `Fun (A : Type) -> A -> A` and `Fun (B : Type) -> B -> B` 127 | /// 128 | /// # References 129 | /// 130 | /// - https://en.wikipedia.org/wiki/Lambda_calculus#Alpha_equivalence 131 | /// - http://wiki.c2.com/?AlphaEquivalence 132 | /// - http://www.twelf.org/wiki/Alpha-equivalence 133 | pub fn alpha_eq(&self, other: &Term) -> bool { 134 | // The implementation of this is pretty straightforward, because we 135 | // are already using De Bruijn indices, so we just need to compare 136 | // variables using regular equality, while avoiding the comparison of 137 | // metadata, such as variable name hints and doc strings. 138 | match (self, other) { 139 | (Term::Var(index1), Term::Var(index2)) => index1 == index2, 140 | (Term::Prim(name1), Term::Prim(name2)) => name1 == name2, 141 | (Term::Ann(term1, term_ty1), Term::Ann(term2, term_ty2)) => { 142 | Term::alpha_eq(term1, term2) && Term::alpha_eq(term_ty1, term_ty2) 143 | }, 144 | (Term::Let(items1, body1), Term::Let(items2, body2)) => { 145 | items1.len() == items2.len() 146 | && Iterator::zip(items1.iter(), items2.iter()).all(|(item1, item2)| { 147 | match (item1, item2) { 148 | (Item::Declaration(_, _, ty1), Item::Declaration(_, _, ty2)) => { 149 | Term::alpha_eq(ty1, ty2) 150 | }, 151 | (Item::Definition(_, _, term1), Item::Definition(_, _, term2)) => { 152 | Term::alpha_eq(term1, term2) 153 | }, 154 | (_, _) => false, 155 | } 156 | }) 157 | && Term::alpha_eq(body1, body2) 158 | }, 159 | 160 | (Term::LiteralType(literal_ty1), Term::LiteralType(literal_ty2)) => { 161 | LiteralType::alpha_eq(literal_ty1, literal_ty2) 162 | }, 163 | (Term::LiteralIntro(literal_intro1), Term::LiteralIntro(literal_intro2)) => { 164 | LiteralIntro::alpha_eq(literal_intro1, literal_intro2) 165 | }, 166 | ( 167 | Term::LiteralElim(scrutinee1, clauses1, default1), 168 | Term::LiteralElim(scrutinee2, clauses2, default2), 169 | ) => { 170 | Term::alpha_eq(scrutinee1, scrutinee2) 171 | && clauses1.len() == clauses2.len() 172 | && Iterator::zip(clauses1.iter(), clauses2.iter()) 173 | .all(|((l1, b1), (l2, b2))| l1 == l2 && Term::alpha_eq(b1, b2)) 174 | && Term::alpha_eq(default1, default2) 175 | }, 176 | 177 | ( 178 | Term::FunType(app_mode1, _, param_ty1, body_ty1), 179 | Term::FunType(app_mode2, _, param_ty2, body_ty2), 180 | ) => { 181 | Term::alpha_eq(param_ty1, param_ty2) 182 | && app_mode1 == app_mode2 183 | && Term::alpha_eq(body_ty1, body_ty2) 184 | }, 185 | (Term::FunIntro(app_mode1, _, body1), Term::FunIntro(app_mode2, _, body2)) => { 186 | app_mode1 == app_mode2 && Term::alpha_eq(body1, body2) 187 | }, 188 | (Term::FunElim(fun1, app_mode1, arg1), Term::FunElim(fun2, app_mode2, arg2)) => { 189 | Term::alpha_eq(fun1, fun2) && app_mode1 == app_mode2 && Term::alpha_eq(arg1, arg2) 190 | }, 191 | 192 | (Term::RecordType(ty_fields1), Term::RecordType(ty_fields2)) => { 193 | ty_fields1.len() == ty_fields2.len() 194 | && Iterator::zip(ty_fields1.iter(), ty_fields2.iter()) 195 | .all(|((_, l1, _, t1), (_, l2, _, t2))| l1 == l2 && Term::alpha_eq(t1, t2)) 196 | }, 197 | (Term::RecordIntro(intro_fields1), Term::RecordIntro(intro_fields2)) => { 198 | intro_fields1.len() == intro_fields2.len() 199 | && Iterator::zip(intro_fields1.iter(), intro_fields2.iter()) 200 | .all(|((l1, t1), (l2, t2))| l1 == l2 && Term::alpha_eq(t1, t2)) 201 | }, 202 | (Term::RecordElim(record1, label1), Term::RecordElim(record2, label2)) => { 203 | Term::alpha_eq(record1, record2) && label1 == label2 204 | }, 205 | 206 | (Term::Universe(level1), Term::Universe(level2)) => level1 == level2, 207 | 208 | (_, _) => false, 209 | } 210 | } 211 | } 212 | 213 | impl fmt::Debug for Term { 214 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 215 | let doc = self.to_debug_doc().group(); 216 | fmt::Display::fmt(&doc.pretty(1_000_000_000), f) 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /crates/mltt-core/src/var.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::ops; 3 | 4 | /// An environment of entries that can be looked up based on a debruijn index. 5 | /// 6 | /// It is backed by an `im::Vector` to allow for efficient sharing between 7 | /// multiple closures. 8 | #[derive(Debug, Clone, PartialEq)] 9 | pub struct Env { 10 | /// The entries in the environment 11 | entries: im::Vector, 12 | } 13 | 14 | impl Env { 15 | /// Create a new, empty environment. 16 | pub fn new() -> Env { 17 | Env { 18 | entries: im::Vector::new(), 19 | } 20 | } 21 | 22 | /// Get the size of the environment. 23 | pub fn size(&self) -> Size { 24 | Size(self.entries.len() as u32) 25 | } 26 | 27 | /// Lookup an entry in the environment. 28 | pub fn lookup_entry(&self, index: Index) -> Option<&Entry> { 29 | self.entries.get(index.0 as usize) 30 | } 31 | 32 | /// Add an entry in the environment. 33 | pub fn add_entry(&mut self, entry: Entry) { 34 | self.entries.push_front(entry); 35 | } 36 | 37 | pub fn entries(&self) -> &im::Vector { 38 | &self.entries 39 | } 40 | } 41 | 42 | /// The size of the environment. 43 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 44 | pub struct Size(pub u32); 45 | 46 | impl Size { 47 | /// Return the level of the next variable to be added to the environment. 48 | pub fn next_level(self) -> Level { 49 | Level(self.0) 50 | } 51 | 52 | /// Convert a variable level to a variable index in the current environment. 53 | pub fn index(self, level: Level) -> Index { 54 | Index(self.0 - (level.0 + 1)) // FIXME: Check for over/underflow? 55 | } 56 | } 57 | 58 | impl From for Size { 59 | fn from(src: u32) -> Size { 60 | Size(src) 61 | } 62 | } 63 | 64 | impl ops::AddAssign for Size { 65 | fn add_assign(&mut self, other: u32) { 66 | self.0 += other; 67 | } 68 | } 69 | 70 | impl ops::Add for Size { 71 | type Output = Size; 72 | 73 | fn add(mut self, other: u32) -> Size { 74 | self += other; 75 | self 76 | } 77 | } 78 | 79 | /// De Bruijn level. 80 | /// 81 | /// This counts the total number of binders that we encounter when running down 82 | /// the syntax tree from the root. 83 | /// 84 | /// De Bruijn levels are useful because unlike de Bruijn indices, they don't 85 | /// need to be shifted while moving around terms under a specific scope. This 86 | /// makes them ideal for representing values. We'll convert these back into 87 | /// indices during read-back. 88 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 89 | pub struct Level(pub u32); 90 | 91 | impl From for Level { 92 | fn from(src: u32) -> Level { 93 | Level(src) 94 | } 95 | } 96 | 97 | impl ops::AddAssign for Level { 98 | fn add_assign(&mut self, other: u32) { 99 | self.0 += other; 100 | } 101 | } 102 | 103 | impl ops::Add for Level { 104 | type Output = Level; 105 | 106 | fn add(mut self, other: u32) -> Level { 107 | self += other; 108 | self 109 | } 110 | } 111 | 112 | impl std::fmt::Display for Level { 113 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 114 | write!(f, "%{}", self.0) 115 | } 116 | } 117 | 118 | /// De Bruijn index. 119 | /// 120 | /// This counts the number of binders we encounter when running up the syntax 121 | /// tree to get to the binder that bound this variable. De Bruijn indices are 122 | /// useful for being able to quickly looking up entries in an `Env` when deep in 123 | /// a nested scope. They also provide easy access to alpha equality. 124 | #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 125 | pub struct Index(pub u32); 126 | 127 | impl From for Index { 128 | fn from(src: u32) -> Index { 129 | Index(src) 130 | } 131 | } 132 | 133 | impl ops::AddAssign for Index { 134 | fn add_assign(&mut self, other: u32) { 135 | self.0 += other; 136 | } 137 | } 138 | 139 | impl ops::Add for Index { 140 | type Output = Index; 141 | 142 | fn add(mut self, other: u32) -> Index { 143 | self += other; 144 | self 145 | } 146 | } 147 | 148 | impl std::fmt::Display for Index { 149 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 150 | write!(f, "@{}", self.0) 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /crates/mltt-elaborate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-elaborate" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "Elaboration of the MLTT language's concrete syntax into its core syntax" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | im = "15.1.0" 12 | language-reporting = { git = "https://github.com/nikomatsakis/language-reporting", branch = "remove-codespan-dep" } 13 | log = "0.4" 14 | mltt-core = { path = "../mltt-core" } 15 | mltt-concrete = { path = "../mltt-concrete" } 16 | mltt-span = { path = "../mltt-span" } 17 | pretty = "0.5" 18 | -------------------------------------------------------------------------------- /crates/mltt-elaborate/src/context.rs: -------------------------------------------------------------------------------- 1 | //! The elaboration context. 2 | 3 | use language_reporting::Diagnostic; 4 | use mltt_core::{domain, meta, prim, syntax, validate, var, AppMode}; 5 | use mltt_span::FileSpan; 6 | use pretty::{BoxDoc, Doc}; 7 | use std::rc::Rc; 8 | 9 | use crate::{nbe, unify}; 10 | 11 | /// Local elaboration context. 12 | /// 13 | /// This stores the information that we need when elaborating terms from the 14 | /// concrete syntax to the core syntax. This includes primitives, values needed 15 | /// for evaluation, and name-to-level substitutions. 16 | /// 17 | /// Persistent data structures are used internally, so it shouldn't be too 18 | /// costly to clone this - for example when entering into new scopes. 19 | #[derive(Debug, Clone)] 20 | pub struct Context { 21 | /// Primitive entries. 22 | prims: prim::Env, 23 | /// Values to be used during evaluation. 24 | values: var::Env>, 25 | /// Types of the entries in the context. 26 | tys: var::Env>, 27 | /// Names of the entries in the context (used for pretty printing). 28 | names: var::Env, 29 | /// Substitutions from the user-defined names to the level in which they 30 | /// were bound. 31 | /// 32 | /// We associate levels to the binder names so that we can recover the 33 | /// correct debruijn index once we reach a variable name in a nested scope. 34 | /// Not all entries in the context will have a corresponding name - for 35 | /// example we don't define a name for non-dependent function types. 36 | names_to_levels: im::HashMap, 37 | /// Local bound levels. 38 | /// 39 | /// This is used for making spines for fresh metas. 40 | bound_levels: im::Vector, 41 | } 42 | 43 | impl Context { 44 | /// Create a new, empty context. 45 | pub fn empty() -> Context { 46 | Context { 47 | prims: prim::Env::new(), 48 | values: var::Env::new(), 49 | tys: var::Env::new(), 50 | names: var::Env::new(), 51 | names_to_levels: im::HashMap::new(), 52 | bound_levels: im::Vector::new(), 53 | } 54 | } 55 | 56 | /// Primitive entries. 57 | pub fn prims(&self) -> &prim::Env { 58 | &self.prims 59 | } 60 | 61 | /// Values to be used during evaluation. 62 | pub fn values(&self) -> &var::Env> { 63 | &self.values 64 | } 65 | 66 | /// Convert the context into a validation context. 67 | pub fn validation_context(&self) -> validate::Context { 68 | validate::Context::new(self.prims.clone(), self.values.clone(), self.tys.clone()) 69 | } 70 | 71 | /// Convert the context into a pretty printing environment. 72 | pub fn pretty_env(&self) -> mltt_core::pretty::Env { 73 | mltt_core::pretty::Env::new(self.names.clone()) 74 | } 75 | 76 | /// Add a name-to-level substitution to the context. 77 | pub fn add_name(&mut self, name: impl Into, var_level: var::Level) { 78 | let name = name.into(); 79 | self.names.add_entry(name.clone()); 80 | self.names_to_levels.insert(name, var_level); 81 | } 82 | 83 | /// Add a fresh definition to the context. 84 | pub fn add_fresh_defn(&mut self, value: Rc, ty: Rc) { 85 | log::trace!("add fresh definition"); 86 | 87 | self.values.add_entry(value); 88 | self.tys.add_entry(ty); 89 | } 90 | 91 | /// Add a definition to the context. 92 | pub fn add_defn( 93 | &mut self, 94 | name: impl Into, 95 | value: Rc, 96 | ty: Rc, 97 | ) { 98 | let name = name.into(); 99 | log::trace!("add definition: {}", name); 100 | 101 | let var_level = self.values.size().next_level(); 102 | self.add_name(name, var_level); 103 | self.values.add_entry(value); 104 | self.tys.add_entry(ty); 105 | } 106 | 107 | /// Add a fresh parameter the context, returning a variable that points to 108 | /// the introduced binder. 109 | pub fn add_fresh_param(&mut self, ty: Rc) -> Rc { 110 | log::trace!("add fresh parameter"); 111 | 112 | let var_level = self.values.size().next_level(); 113 | let value = Rc::from(domain::Value::var(var_level)); 114 | self.values.add_entry(value.clone()); 115 | self.tys.add_entry(ty); 116 | self.bound_levels.push_back(var_level); 117 | value 118 | } 119 | 120 | /// Add a parameter the context, returning a variable that points to 121 | /// the introduced binder. 122 | pub fn add_param( 123 | &mut self, 124 | name: impl Into, 125 | ty: Rc, 126 | ) -> Rc { 127 | let name = name.into(); 128 | log::trace!("add parameter: {}", name); 129 | 130 | let var_level = self.values.size().next_level(); 131 | self.add_name(name, var_level); 132 | let value = Rc::from(domain::Value::var(var_level)); 133 | self.values.add_entry(value.clone()); 134 | self.tys.add_entry(ty); 135 | self.bound_levels.push_back(var_level); 136 | value 137 | } 138 | 139 | /// Create a fresh meta and return the meta applied to all of the currently 140 | /// bound vars. 141 | pub fn new_meta( 142 | &self, 143 | metas: &mut meta::Env, 144 | span: FileSpan, 145 | ty: Rc, 146 | ) -> Rc { 147 | let args = self.bound_levels.iter().map(|var_level| { 148 | let var_index = self.values().size().index(*var_level); 149 | Rc::from(syntax::Term::var(var_index)) 150 | }); 151 | 152 | args.fold( 153 | Rc::from(syntax::Term::Meta(metas.add_unsolved(span, ty))), 154 | |acc, arg| Rc::from(syntax::Term::FunElim(acc, AppMode::Explicit, arg)), 155 | ) 156 | } 157 | 158 | /// Lookup the de-bruijn index and the type annotation of a binder in the 159 | /// context using a user-defined name. 160 | pub fn lookup_binder(&self, name: &str) -> Option<(var::Index, &Rc)> { 161 | let var_level = self.names_to_levels.get(name)?; 162 | let var_index = self.values().size().index(*var_level); 163 | let ty = self.tys.lookup_entry(var_index)?; 164 | log::trace!("lookup binder: {} -> {}", name, var_index); 165 | Some((var_index, ty)) 166 | } 167 | 168 | /// Apply a closure to an argument. 169 | pub fn app_closure( 170 | &self, 171 | metas: &meta::Env, 172 | closure: &domain::AppClosure, 173 | arg: Rc, 174 | ) -> Result, Diagnostic> { 175 | nbe::app_closure(self.prims(), metas, closure, arg) 176 | } 177 | 178 | /// Evaluate a term using the evaluation environment 179 | pub fn eval_term( 180 | &self, 181 | metas: &meta::Env, 182 | span: impl Into>, 183 | term: &Rc, 184 | ) -> Result, Diagnostic> { 185 | nbe::eval_term(self.prims(), metas, self.values(), span, term) 186 | } 187 | 188 | /// Read a value back into the core syntax, normalizing as required. 189 | pub fn read_back_value( 190 | &self, 191 | metas: &meta::Env, 192 | span: impl Into>, 193 | value: &Rc, 194 | ) -> Result, Diagnostic> { 195 | nbe::read_back_value(self.prims(), metas, self.values().size(), span, value) 196 | } 197 | 198 | /// Fully normalize a term by first evaluating it, then reading it back. 199 | pub fn normalize_term( 200 | &self, 201 | metas: &meta::Env, 202 | span: impl Into>, 203 | term: &Rc, 204 | ) -> Result, Diagnostic> { 205 | nbe::normalize_term(self.prims(), metas, self.values(), span, term) 206 | } 207 | 208 | /// Evaluate a value further, if it's now possible due to updates made to the 209 | /// metavariable solutions. 210 | pub fn force_value( 211 | &self, 212 | metas: &meta::Env, 213 | span: impl Into>, 214 | value: &Rc, 215 | ) -> Result, Diagnostic> { 216 | nbe::force_value(self.prims(), metas, span, value) 217 | } 218 | 219 | /// Expect that `ty1` is a subtype of `ty2` in the current context 220 | pub fn unify_values( 221 | &self, 222 | metas: &mut meta::Env, 223 | span: FileSpan, 224 | value1: &Rc, 225 | value2: &Rc, 226 | ) -> Result<(), Diagnostic> { 227 | unify::unify_values(self.prims(), metas, self.values(), span, value1, value2) 228 | } 229 | 230 | /// Convert a term to a pretty printable document. 231 | pub fn term_to_doc(&self, term: &Rc) -> Doc<'_, BoxDoc<'_, ()>> { 232 | term.to_display_doc(&self.pretty_env()) 233 | } 234 | 235 | /// Convert a value to a pretty printable document. 236 | pub fn value_to_doc( 237 | &self, 238 | metas: &meta::Env, 239 | value: &Rc, 240 | ) -> Doc<'_, BoxDoc<'_, ()>> { 241 | match self.read_back_value(metas, None, value) { 242 | Ok(term) => term.to_display_doc(&self.pretty_env()), 243 | Err(_) => Doc::text(""), 244 | } 245 | } 246 | } 247 | 248 | impl Default for Context { 249 | fn default() -> Context { 250 | use mltt_core::domain::Value; 251 | use mltt_core::literal::LiteralType as LitType; 252 | 253 | let mut context = Context::empty(); 254 | let u0 = Rc::from(Value::universe(0)); 255 | let bool = Rc::from(Value::literal_ty(LitType::Bool)); 256 | 257 | context.add_defn( 258 | "String", 259 | Rc::from(Value::literal_ty(LitType::String)), 260 | u0.clone(), 261 | ); 262 | context.add_defn( 263 | "Char", 264 | Rc::from(Value::literal_ty(LitType::Char)), 265 | u0.clone(), 266 | ); 267 | context.add_defn("Bool", bool.clone(), u0.clone()); 268 | context.add_defn("true", Rc::from(Value::literal_intro(true)), bool.clone()); 269 | context.add_defn("false", Rc::from(Value::literal_intro(false)), bool.clone()); 270 | context.add_defn("U8", Rc::from(Value::literal_ty(LitType::U8)), u0.clone()); 271 | context.add_defn("U16", Rc::from(Value::literal_ty(LitType::U16)), u0.clone()); 272 | context.add_defn("U32", Rc::from(Value::literal_ty(LitType::U32)), u0.clone()); 273 | context.add_defn("U64", Rc::from(Value::literal_ty(LitType::U64)), u0.clone()); 274 | context.add_defn("S8", Rc::from(Value::literal_ty(LitType::S8)), u0.clone()); 275 | context.add_defn("S16", Rc::from(Value::literal_ty(LitType::S16)), u0.clone()); 276 | context.add_defn("S32", Rc::from(Value::literal_ty(LitType::S32)), u0.clone()); 277 | context.add_defn("S64", Rc::from(Value::literal_ty(LitType::S64)), u0.clone()); 278 | context.add_defn("F32", Rc::from(Value::literal_ty(LitType::F32)), u0.clone()); 279 | context.add_defn("F64", Rc::from(Value::literal_ty(LitType::F64)), u0.clone()); 280 | 281 | context.prims = prim::Env::default(); 282 | 283 | context 284 | } 285 | } 286 | 287 | #[cfg(test)] 288 | mod test { 289 | use super::*; 290 | 291 | #[test] 292 | fn add_params() { 293 | use mltt_core::domain::Value; 294 | 295 | let mut context = Context::empty(); 296 | 297 | let ty1 = Rc::from(Value::universe(0)); 298 | let ty2 = Rc::from(Value::universe(1)); 299 | let ty3 = Rc::from(Value::universe(2)); 300 | 301 | let param1 = context.add_param("x", ty1.clone()); 302 | let param2 = context.add_param("y", ty2.clone()); 303 | let param3 = context.add_param("z", ty3.clone()); 304 | 305 | assert_eq!(param1, Rc::from(Value::var(0))); 306 | assert_eq!(param2, Rc::from(Value::var(1))); 307 | assert_eq!(param3, Rc::from(Value::var(2))); 308 | 309 | assert_eq!(context.lookup_binder("x").unwrap().1, &ty1); 310 | assert_eq!(context.lookup_binder("y").unwrap().1, &ty2); 311 | assert_eq!(context.lookup_binder("z").unwrap().1, &ty3); 312 | } 313 | 314 | #[test] 315 | fn add_params_shadow() { 316 | use mltt_core::domain::Value; 317 | 318 | let mut context = Context::empty(); 319 | 320 | let ty1 = Rc::from(Value::universe(0)); 321 | let ty2 = Rc::from(Value::universe(1)); 322 | let ty3 = Rc::from(Value::universe(2)); 323 | 324 | let param1 = context.add_param("x", ty1.clone()); 325 | let param2 = context.add_param("x", ty2.clone()); 326 | let param3 = context.add_param("x", ty3.clone()); 327 | 328 | assert_eq!(param1, Rc::from(Value::var(0))); 329 | assert_eq!(param2, Rc::from(Value::var(1))); 330 | assert_eq!(param3, Rc::from(Value::var(2))); 331 | 332 | assert_eq!(context.lookup_binder("x").unwrap().1, &ty3); 333 | } 334 | 335 | #[test] 336 | fn add_params_fresh() { 337 | use mltt_core::domain::Value; 338 | 339 | let mut context = Context::empty(); 340 | 341 | let ty1 = Rc::from(Value::universe(0)); 342 | let ty2 = Rc::from(Value::universe(1)); 343 | let ty3 = Rc::from(Value::universe(2)); 344 | 345 | let param1 = context.add_param("x", ty1.clone()); 346 | let param2 = context.add_fresh_param(ty2.clone()); 347 | let param3 = context.add_fresh_param(ty3.clone()); 348 | 349 | assert_eq!(param1, Rc::from(Value::var(0))); 350 | assert_eq!(param2, Rc::from(Value::var(1))); 351 | assert_eq!(param3, Rc::from(Value::var(2))); 352 | 353 | assert_eq!(context.lookup_binder("x").unwrap().1, &ty1); 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /crates/mltt-elaborate/src/literal.rs: -------------------------------------------------------------------------------- 1 | //! Elaboration of literals from unicode strings into their respective core 2 | //! syntax representations. 3 | //! 4 | //! We need to defer the final parsing of literals until elaboration time 5 | //! because it is only now that we know how large our target types are. This 6 | //! saves us from having to use big integers or floats in our concrete syntax. 7 | //! 8 | //! Ultimately it would be pretty cool if you could register your own parse 9 | //! functions that would be able to convert (at elaboration time) a UTF-8 string 10 | //! into a data type of your choice, or return a custom error diagnostic. 11 | 12 | use language_reporting::{Diagnostic, Label as DiagnosticLabel}; 13 | use mltt_concrete::{LiteralKind, SpannedString}; 14 | use mltt_core::literal::LiteralIntro; 15 | use mltt_core::{domain, meta}; 16 | use mltt_span::FileSpan; 17 | use std::fmt; 18 | use std::rc::Rc; 19 | 20 | use super::Context; 21 | 22 | /// Check the type of a literal in a context. 23 | pub fn check( 24 | context: &Context, 25 | metas: &meta::Env, 26 | kind: LiteralKind, 27 | src: &SpannedString<'_>, 28 | expected_ty: &Rc, 29 | ) -> Result> { 30 | use mltt_concrete::LiteralKind as LitKind; 31 | use mltt_core::domain::Value::LiteralType; 32 | use mltt_core::literal::{LiteralIntro as LitIntro, LiteralType as LitType}; 33 | 34 | match (kind, expected_ty.as_ref()) { 35 | (LitKind::String, LiteralType(LitType::String)) => { 36 | parse_string(src).map(Rc::from).map(LitIntro::String) 37 | }, 38 | (LitKind::Char, LiteralType(LitType::Char)) => parse_char(src).map(LitIntro::Char), 39 | (LitKind::Int, LiteralType(LitType::U8)) => parse_int::(src).map(LitIntro::U8), 40 | (LitKind::Int, LiteralType(LitType::U16)) => parse_int::(src).map(LitIntro::U16), 41 | (LitKind::Int, LiteralType(LitType::U32)) => parse_int::(src).map(LitIntro::U32), 42 | (LitKind::Int, LiteralType(LitType::U64)) => parse_int::(src).map(LitIntro::U64), 43 | (LitKind::Int, LiteralType(LitType::S8)) => parse_int::(src).map(LitIntro::S8), 44 | (LitKind::Int, LiteralType(LitType::S16)) => parse_int::(src).map(LitIntro::S16), 45 | (LitKind::Int, LiteralType(LitType::S32)) => parse_int::(src).map(LitIntro::S32), 46 | (LitKind::Int, LiteralType(LitType::S64)) => parse_int::(src).map(LitIntro::S64), 47 | (LitKind::Float, LiteralType(LitType::F32)) => parse_float::(src).map(LitIntro::F32), 48 | (LitKind::Float, LiteralType(LitType::F64)) => parse_float::(src).map(LitIntro::F64), 49 | (_, _) => Err(Diagnostic::new_error("mismatched literal").with_label( 50 | DiagnosticLabel::new_primary(src.span()).with_message(format!( 51 | "expected: {}", 52 | context 53 | .value_to_doc(metas, &expected_ty) 54 | .pretty(1000_000_000), 55 | )), 56 | )), 57 | } 58 | } 59 | 60 | /// Synthesize the type of a literal. 61 | pub fn synth( 62 | kind: LiteralKind, 63 | src: &SpannedString<'_>, 64 | ) -> Result<(LiteralIntro, Rc), Diagnostic> { 65 | use mltt_concrete::LiteralKind as LitKind; 66 | use mltt_core::literal::{LiteralIntro as LitIntro, LiteralType as LitType}; 67 | 68 | match kind { 69 | LitKind::String => Ok(( 70 | LitIntro::String(Rc::from(parse_string(src)?)), 71 | Rc::from(domain::Value::literal_ty(LitType::String)), 72 | )), 73 | LitKind::Char => Ok(( 74 | LitIntro::Char(parse_char(src)?), 75 | Rc::from(domain::Value::literal_ty(LitType::Char)), 76 | )), 77 | LitKind::Int | LitKind::Float => Err(Diagnostic::new_error("ambiguous literal") 78 | .with_label(DiagnosticLabel::new_primary(src.span()))), 79 | } 80 | } 81 | 82 | fn literal_bug(span: FileSpan, message: impl Into) -> Result> { 83 | // FIXME: improve precision of error span 84 | Err(Diagnostic::new_bug(message).with_label(DiagnosticLabel::new_primary(span))) 85 | } 86 | 87 | fn expect_char( 88 | span: FileSpan, 89 | chars: &mut impl Iterator, 90 | ) -> Result> { 91 | match chars.next() { 92 | Some(ch) => Ok(ch), 93 | None => literal_bug(span, "unexpected EOF"), 94 | } 95 | } 96 | 97 | pub fn parse_string(src: &SpannedString<'_>) -> Result> { 98 | let mut chars = src.slice.chars(); 99 | let mut string = String::new(); 100 | 101 | assert_eq!(chars.next(), Some('"')); 102 | 103 | loop { 104 | match expect_char(src.span(), &mut chars)? { 105 | '"' => break, 106 | '\\' => string.push(parse_escape(src.span(), &mut chars)?), 107 | ch => string.push(ch), 108 | } 109 | } 110 | 111 | assert_eq!(chars.next(), None); 112 | 113 | Ok(string) 114 | } 115 | 116 | pub fn parse_char(src: &SpannedString<'_>) -> Result> { 117 | let mut chars = src.slice.chars(); 118 | 119 | assert_eq!(chars.next(), Some('\'')); 120 | 121 | let ch = match expect_char(src.span(), &mut chars)? { 122 | '\'' => literal_bug(src.span(), "unexpected end of character"), 123 | '\\' => parse_escape(src.span(), &mut chars), 124 | ch => Ok(ch), 125 | }?; 126 | 127 | assert_eq!(chars.next(), Some('\'')); 128 | assert_eq!(chars.next(), None); 129 | 130 | Ok(ch) 131 | } 132 | 133 | fn parse_escape( 134 | span: FileSpan, 135 | chars: &mut impl Iterator, 136 | ) -> Result> { 137 | match expect_char(span, chars)? { 138 | '\'' => Ok('\''), 139 | '\"' => Ok('\"'), 140 | '\\' => Ok('\\'), 141 | 'n' => Ok('\n'), 142 | 'r' => Ok('\r'), 143 | 't' => Ok('\t'), 144 | '0' => Ok('\0'), 145 | 'x' => { 146 | let mut code = 0; 147 | 148 | match expect_char(span, chars)? { 149 | ch @ '0'..='7' => code = code * 16 + (ch as u32 - '0' as u32), 150 | _ => literal_bug(span, "invalid ascii escape")?, 151 | }; 152 | 153 | match expect_char(span, chars)? { 154 | ch @ '0'..='9' => code = code * 16 + (ch as u32 - '0' as u32), 155 | ch @ 'a'..='f' => code = code * 16 + (ch as u32 - 'a' as u32 + 10), 156 | ch @ 'A'..='F' => code = code * 16 + (ch as u32 - 'A' as u32 + 10), 157 | _ => literal_bug(span, "invalid ascii escape")?, 158 | }; 159 | 160 | match std::char::from_u32(code) { 161 | Some(ch) => Ok(ch), 162 | None => literal_bug(span, "invalid ascii escape"), 163 | } 164 | }, 165 | 'u' => { 166 | let mut code = 0; 167 | 168 | assert_eq!(chars.next(), Some('{')); 169 | loop { 170 | match expect_char(span, chars)? { 171 | ch @ '0'..='9' => code = code * 16 + (ch as u32 - '0' as u32), 172 | ch @ 'a'..='f' => code = code * 16 + (ch as u32 - 'a' as u32 + 10), 173 | ch @ 'A'..='F' => code = code * 16 + (ch as u32 - 'A' as u32 + 10), 174 | '_' => continue, 175 | '}' => break, 176 | _ => literal_bug(span, "invalid unicode escape")?, 177 | } 178 | } 179 | 180 | match std::char::from_u32(code) { 181 | Some(ch) => Ok(ch), 182 | None => literal_bug(span, "invalid unicode escape"), 183 | } 184 | }, 185 | _ => literal_bug(span, "unknown escape code"), 186 | } 187 | } 188 | 189 | /// Helper trait for defining `parse_int`. 190 | pub trait ParseIntLiteral: Sized + fmt::Display + fmt::Binary + fmt::Octal + fmt::LowerHex { 191 | const MIN: Self; 192 | const MAX: Self; 193 | fn from_u8(num: u8) -> Self; 194 | fn checked_neg(self) -> Option; 195 | fn checked_add(self, other: Self) -> Option; 196 | fn checked_mul(self, other: Self) -> Option; 197 | } 198 | 199 | macro_rules! impl_parse_int_literal { 200 | ($T:ident) => { 201 | impl ParseIntLiteral for $T { 202 | const MIN: $T = std::$T::MIN; 203 | const MAX: $T = std::$T::MAX; 204 | 205 | fn from_u8(num: u8) -> $T { 206 | num as $T 207 | } 208 | 209 | fn checked_neg(self) -> Option<$T> { 210 | $T::checked_neg(self) 211 | } 212 | 213 | fn checked_add(self, other: $T) -> Option<$T> { 214 | $T::checked_add(self, other) 215 | } 216 | 217 | fn checked_mul(self, other: $T) -> Option<$T> { 218 | $T::checked_mul(self, other) 219 | } 220 | } 221 | }; 222 | } 223 | 224 | impl_parse_int_literal!(u8); 225 | impl_parse_int_literal!(u16); 226 | impl_parse_int_literal!(u32); 227 | impl_parse_int_literal!(u64); 228 | impl_parse_int_literal!(i8); 229 | impl_parse_int_literal!(i16); 230 | impl_parse_int_literal!(i32); 231 | impl_parse_int_literal!(i64); 232 | 233 | fn int_range_message(radix: u8) -> String { 234 | match radix { 235 | 2 => format!( 236 | "expected an integer from `{:#b}` to `{:#b}`", 237 | T::MIN, 238 | T::MAX, 239 | ), 240 | 8 => format!( 241 | "expected an integer from `{:#o}` to `{:#o}`", 242 | T::MIN, 243 | T::MAX, 244 | ), 245 | 16 => format!( 246 | "expected an integer from `{:#x}` to `{:#x}`", 247 | T::MIN, 248 | T::MAX, 249 | ), 250 | _ => format!("expected an integer from `{}` to `{}`", T::MIN, T::MAX), 251 | } 252 | } 253 | 254 | pub fn parse_int(src: &SpannedString<'_>) -> Result> { 255 | let span = src.span(); 256 | let mut chars = src.slice.chars(); 257 | 258 | fn expect_base( 259 | span: FileSpan, 260 | is_neg: bool, 261 | chars: &mut impl Iterator, 262 | ) -> Result<(bool, u8, Option), Diagnostic> { 263 | match chars.next() { 264 | None => Ok((is_neg, 10, None)), 265 | Some('b') => Ok((is_neg, 2, None)), 266 | Some('o') => Ok((is_neg, 8, None)), 267 | Some('x') => Ok((is_neg, 16, None)), 268 | Some('_') => Ok((is_neg, 10, None)), 269 | Some(ch @ '0'..='9') => Ok((is_neg, 10, Some(ch))), 270 | Some(_) => literal_bug(span, "unexpected character")?, 271 | } 272 | } 273 | 274 | let (is_neg, base, mut first_digit) = match expect_char(span, &mut chars)? { 275 | '-' => match expect_char(span, &mut chars)? { 276 | '0' => expect_base(span, true, &mut chars)?, 277 | ch @ '0'..='9' => (true, 10, Some(ch)), 278 | _ => literal_bug(span, "unexpected character")?, 279 | }, 280 | '0' => expect_base(span, false, &mut chars)?, 281 | ch @ '0'..='9' => (false, 10, Some(ch)), 282 | _ => literal_bug(span, "unexpected character")?, 283 | }; 284 | 285 | let from_char = |ch: char, ch_diff: char, off: u8| { 286 | let number = T::from_u8(ch as u8 - ch_diff as u8 + off); 287 | 288 | if is_neg { 289 | number.checked_neg().ok_or_else(|| { 290 | Diagnostic::new_error("underflowing literal").with_label( 291 | DiagnosticLabel::new_primary(span).with_message(int_range_message::(base)), 292 | ) 293 | }) 294 | } else { 295 | Ok(number) 296 | } 297 | }; 298 | 299 | let acc = |prev: T, base: u8, inc: T| { 300 | if is_neg { 301 | prev.checked_mul(T::from_u8(base)) 302 | .and_then(|prev| prev.checked_add(inc)) 303 | .ok_or_else(|| { 304 | Diagnostic::new_error("underflowing literal").with_label( 305 | DiagnosticLabel::new_primary(span) 306 | .with_message(int_range_message::(base)), 307 | ) 308 | }) 309 | } else { 310 | prev.checked_mul(T::from_u8(base)) 311 | .and_then(|prev| prev.checked_add(inc)) 312 | .ok_or_else(|| { 313 | Diagnostic::new_error("overflowing literal").with_label( 314 | DiagnosticLabel::new_primary(span) 315 | .with_message(int_range_message::(base)), 316 | ) 317 | }) 318 | } 319 | }; 320 | 321 | let mut number = T::from_u8(0); 322 | 323 | while let Some(ch) = first_digit.take().or_else(|| chars.next()) { 324 | number = match (base, ch) { 325 | (2, ch @ '0'..='1') => acc(number, base, from_char(ch, '0', 0)?)?, 326 | (8, ch @ '0'..='7') => acc(number, base, from_char(ch, '0', 0)?)?, 327 | (10, ch @ '0'..='9') => acc(number, base, from_char(ch, '0', 0)?)?, 328 | (16, ch @ '0'..='9') => acc(number, base, from_char(ch, '0', 0)?)?, 329 | (16, ch @ 'a'..='f') => acc(number, base, from_char(ch, 'a', 10)?)?, 330 | (16, ch @ 'A'..='F') => acc(number, base, from_char(ch, 'A', 10)?)?, 331 | (_, '_') => continue, 332 | (_, _) => literal_bug(span, "unexpected character")?, 333 | }; 334 | } 335 | 336 | Ok(number) 337 | } 338 | 339 | /// Helper trait for defining `parse_float`. 340 | pub trait ParseFloatLiteral: Sized {} 341 | 342 | macro_rules! impl_parse_float_literal { 343 | ($T:ident) => { 344 | impl ParseFloatLiteral for $T {} 345 | }; 346 | } 347 | 348 | impl_parse_float_literal!(f32); 349 | impl_parse_float_literal!(f64); 350 | 351 | pub fn parse_float( 352 | src: &SpannedString<'_>, 353 | ) -> Result> { 354 | literal_bug( 355 | src.span(), 356 | "literal elaboration not yet implemented for floats", 357 | ) 358 | } 359 | -------------------------------------------------------------------------------- /crates/mltt-elaborate/src/nbe.rs: -------------------------------------------------------------------------------- 1 | //! Wrappers around the core NBE functions that return diagnostics on errors. 2 | 3 | use language_reporting::{Diagnostic, Label as DiagnosticLabel}; 4 | use mltt_core::{domain, meta, nbe, prim, syntax, var, AppMode, Label}; 5 | use mltt_span::FileSpan; 6 | use std::rc::Rc; 7 | 8 | pub fn eval_fun_elim( 9 | prims: &prim::Env, 10 | metas: &meta::Env, 11 | fun: Rc, 12 | app_mode: &AppMode, 13 | arg: Rc, 14 | ) -> Result, Diagnostic> { 15 | nbe::eval_fun_elim(prims, metas, fun, app_mode, arg) 16 | .map_err(|error| Diagnostic::new_bug(format!("failed function elimination: {}", error))) 17 | } 18 | 19 | pub fn eval_literal_elim( 20 | prims: &prim::Env, 21 | metas: &meta::Env, 22 | scrutinee: Rc, 23 | closure: domain::LiteralClosure, 24 | ) -> Result, Diagnostic> { 25 | nbe::eval_literal_elim(prims, metas, scrutinee, closure) 26 | .map_err(|error| Diagnostic::new_bug(format!("failed literal elimination: {}", error))) 27 | } 28 | 29 | pub fn eval_record_elim( 30 | term: Rc, 31 | label: &Label, 32 | ) -> Result, Diagnostic> { 33 | nbe::eval_record_elim(term, label) 34 | .map_err(|error| Diagnostic::new_bug(format!("failed record elimination: {}", error))) 35 | } 36 | 37 | pub fn app_closure( 38 | prims: &prim::Env, 39 | metas: &meta::Env, 40 | closure: &domain::AppClosure, 41 | arg: Rc, 42 | ) -> Result, Diagnostic> { 43 | nbe::app_closure(prims, metas, closure, arg) 44 | .map_err(|error| Diagnostic::new_bug(format!("failed closure application: {}", error))) 45 | } 46 | 47 | pub fn eval_term( 48 | prims: &prim::Env, 49 | metas: &meta::Env, 50 | values: &var::Env>, 51 | span: impl Into>, 52 | term: &Rc, 53 | ) -> Result, Diagnostic> { 54 | nbe::eval_term(prims, metas, values, term).map_err(|error| match span.into() { 55 | None => Diagnostic::new_bug(format!("failed to evaluate term: {}", error)), 56 | Some(span) => Diagnostic::new_bug("failed to evaluate term") 57 | .with_label(DiagnosticLabel::new_primary(span).with_message(error)), 58 | }) 59 | } 60 | 61 | pub fn read_back_value( 62 | prims: &prim::Env, 63 | metas: &meta::Env, 64 | env_size: var::Size, 65 | span: impl Into>, 66 | value: &Rc, 67 | ) -> Result, Diagnostic> { 68 | nbe::read_back_value(prims, metas, env_size, value).map_err(|error| match span.into() { 69 | None => Diagnostic::new_bug(format!("failed to read-back value: {}", error)), 70 | Some(span) => Diagnostic::new_bug("failed to read-back value") 71 | .with_label(DiagnosticLabel::new_primary(span).with_message(error)), 72 | }) 73 | } 74 | 75 | pub fn normalize_term( 76 | prims: &prim::Env, 77 | metas: &meta::Env, 78 | values: &var::Env>, 79 | span: impl Into>, 80 | term: &Rc, 81 | ) -> Result, Diagnostic> { 82 | nbe::normalize_term(prims, metas, values, term).map_err(|error| match span.into() { 83 | None => Diagnostic::new_bug(format!("failed to normalize term: {}", error)), 84 | Some(span) => Diagnostic::new_bug("failed to normalize term") 85 | .with_label(DiagnosticLabel::new_primary(span).with_message(error)), 86 | }) 87 | } 88 | 89 | pub fn force_value( 90 | prims: &prim::Env, 91 | metas: &meta::Env, 92 | span: impl Into>, 93 | value: &Rc, 94 | ) -> Result, Diagnostic> { 95 | nbe::force_value(prims, metas, value).map_err(|error| match span.into() { 96 | None => Diagnostic::new_bug(format!("failed to force value: {}", error)), 97 | Some(span) => Diagnostic::new_bug("failed to force value") 98 | .with_label(DiagnosticLabel::new_primary(span).with_message(error)), 99 | }) 100 | } 101 | -------------------------------------------------------------------------------- /crates/mltt-parse/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-parse" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "The parser for the MLTT language" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | language-reporting = { git = "https://github.com/nikomatsakis/language-reporting", branch = "remove-codespan-dep" } 12 | log = "0.4" 13 | mltt-concrete = { path = "../mltt-concrete" } 14 | mltt-span = { path = "../mltt-span" } 15 | pretty_assertions = "0.6" 16 | 17 | [dev-dependencies] 18 | pretty_env_logger = "0.3" 19 | -------------------------------------------------------------------------------- /crates/mltt-parse/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! The parser for the MLTT language. 2 | 3 | #![warn(rust_2018_idioms)] 4 | 5 | pub mod lexer; 6 | pub mod parser; 7 | pub mod token; 8 | -------------------------------------------------------------------------------- /crates/mltt-parse/src/token.rs: -------------------------------------------------------------------------------- 1 | use mltt_concrete::SpannedString; 2 | use mltt_span::FileSpan; 3 | use std::fmt; 4 | 5 | /// A kind of delimiter. 6 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 7 | pub enum DelimKind { 8 | /// A round parenthesis: `(` or `)`. 9 | Paren, 10 | /// A curly brace: `{` or `}`. 11 | Brace, 12 | /// A square bracket: `[` or `]`. 13 | Bracket, 14 | } 15 | 16 | /// A tag that makes it easier to remember what type of token this is. 17 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 18 | pub enum TokenKind { 19 | Error, 20 | 21 | Whitespace, 22 | LineComment, 23 | LineDoc, 24 | 25 | Keyword, 26 | Symbol, 27 | Identifier, 28 | StringLiteral, 29 | CharLiteral, 30 | IntLiteral, 31 | FloatLiteral, 32 | 33 | Caret, 34 | Colon, 35 | Dot, 36 | Equals, 37 | Question, 38 | RArrow, 39 | RFatArrow, 40 | 41 | Comma, 42 | Semicolon, 43 | 44 | Open(DelimKind), 45 | Close(DelimKind), 46 | } 47 | 48 | /// A token in the source file, to be emitted by the `Lexer`. 49 | #[derive(Clone, PartialEq, Eq)] 50 | pub struct Token<'file> { 51 | /// The token kind. 52 | pub kind: TokenKind, 53 | /// The source code that produced the token. 54 | pub src: SpannedString<'file>, 55 | } 56 | 57 | impl Token<'_> { 58 | pub fn span(&self) -> FileSpan { 59 | self.src.span() 60 | } 61 | 62 | pub fn is_whitespace(&self) -> bool { 63 | self.kind == TokenKind::Whitespace || self.kind == TokenKind::LineComment 64 | } 65 | 66 | pub fn is_keyword(&self, slice: &str) -> bool { 67 | self.kind == TokenKind::Keyword && self.src.slice == slice 68 | } 69 | } 70 | 71 | impl fmt::Debug for Token<'_> { 72 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 73 | write!(f, "{kind:?}@{src:?}", kind = self.kind, src = self.src) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /crates/mltt-parse/tests/lexer.rs: -------------------------------------------------------------------------------- 1 | use mltt_concrete::SpannedString; 2 | use mltt_parse::lexer::Lexer; 3 | use mltt_parse::token::{DelimKind, Token, TokenKind}; 4 | use mltt_span::{ByteIndex, Files}; 5 | use pretty_assertions::assert_eq; 6 | 7 | /// A handy macro to give us a nice syntax for declaring test cases 8 | /// 9 | /// This was inspired by the tests in the LALRPOP lexer 10 | macro_rules! test { 11 | ($src:expr, $($span:expr => $token_kind:expr,)*) => {{ 12 | let _ = pretty_env_logger::try_init(); 13 | 14 | let mut files = Files::new(); 15 | let src = $src; 16 | let file_id = files.add("test", src); 17 | let lexed_tokens: Vec<_> = Lexer::new(&files[file_id]) 18 | .map(|result| result) 19 | .collect(); 20 | let expected_tokens = vec![$({ 21 | let start = $span.find("~").unwrap(); 22 | let end = $span.rfind("~").unwrap() + 1; 23 | let token_src = SpannedString::new(file_id, ByteIndex::from(start), &src[start..end]); 24 | Token { kind: $token_kind, src: token_src } 25 | }),*]; 26 | 27 | assert_eq!(lexed_tokens, expected_tokens); 28 | }}; 29 | } 30 | 31 | #[test] 32 | fn data() { 33 | test! { 34 | " hello-hahaha8ABC ", 35 | "~~ " => TokenKind::Whitespace, 36 | " ~~~~~~~~~~~~~~~~ " => TokenKind::Identifier, 37 | " ~~" => TokenKind::Whitespace, 38 | }; 39 | } 40 | 41 | #[test] 42 | fn comment() { 43 | test! { 44 | " -- hello this is dog\n ", 45 | "~~~~~~~ " => TokenKind::Whitespace, 46 | " ~~~~~~~~~~~~~~~~~~~~ " => TokenKind::LineComment, 47 | " ~~~ " => TokenKind::Whitespace, 48 | }; 49 | } 50 | 51 | #[test] 52 | fn line_doc() { 53 | test! { 54 | " ||| hello this is dog", 55 | "~~~~~~~ " => TokenKind::Whitespace, 56 | " ~~~~~~~~~~~~~~~~~~~~~" => TokenKind::LineDoc, 57 | }; 58 | } 59 | 60 | #[test] 61 | fn string_literal() { 62 | test! { 63 | r#" "a" "\t" "hello \x3f \x7F \u{7fff} \u{7FFF}" "#, 64 | r#"~~ "# => TokenKind::Whitespace, 65 | r#" ~~~ "# => TokenKind::StringLiteral, 66 | r#" ~ "# => TokenKind::Whitespace, 67 | r#" ~~~~ "# => TokenKind::StringLiteral, 68 | r#" ~ "# => TokenKind::Whitespace, 69 | r#" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "# => TokenKind::StringLiteral, 70 | r#" ~~"# => TokenKind::Whitespace, 71 | }; 72 | } 73 | 74 | #[test] 75 | fn char_literal() { 76 | test! { 77 | r" 'a' '\t' ", 78 | r"~~ " => TokenKind::Whitespace, 79 | r" ~~~ " => TokenKind::CharLiteral, 80 | r" ~ " => TokenKind::Whitespace, 81 | r" ~~~~ " => TokenKind::CharLiteral, 82 | r" ~~" => TokenKind::Whitespace, 83 | }; 84 | } 85 | 86 | #[test] 87 | fn bin_literal() { 88 | test! { 89 | " 0b010110 -0b010110 ", 90 | "~~ " => TokenKind::Whitespace, 91 | " ~~~~~~~~ " => TokenKind::IntLiteral, 92 | " ~~ " => TokenKind::Whitespace, 93 | " ~~~~~~~~~ " => TokenKind::IntLiteral, 94 | " ~~" => TokenKind::Whitespace, 95 | }; 96 | } 97 | 98 | #[test] 99 | fn oct_literal() { 100 | test! { 101 | " 0o12371 -0o12371 ", 102 | "~~ " => TokenKind::Whitespace, 103 | " ~~~~~~~ " => TokenKind::IntLiteral, 104 | " ~~ " => TokenKind::Whitespace, 105 | " ~~~~~~~~ " => TokenKind::IntLiteral, 106 | " ~~" => TokenKind::Whitespace, 107 | }; 108 | } 109 | 110 | #[test] 111 | fn dec_literal() { 112 | test! { 113 | " 123 0 1 2345_65_32 -2345_65_32 ", 114 | "~~ " => TokenKind::Whitespace, 115 | " ~~~ " => TokenKind::IntLiteral, 116 | " ~ " => TokenKind::Whitespace, 117 | " ~ " => TokenKind::IntLiteral, 118 | " ~ " => TokenKind::Whitespace, 119 | " ~ " => TokenKind::IntLiteral, 120 | " ~ " => TokenKind::Whitespace, 121 | " ~~~~~~~~~~ " => TokenKind::IntLiteral, 122 | " ~ " => TokenKind::Whitespace, 123 | " ~~~~~~~~~~~ " => TokenKind::IntLiteral, 124 | " ~~" => TokenKind::Whitespace, 125 | }; 126 | } 127 | 128 | #[test] 129 | fn hex_literal() { 130 | test! { 131 | " 0x123AF -0x123AF ", 132 | "~~ " => TokenKind::Whitespace, 133 | " ~~~~~~~ " => TokenKind::IntLiteral, 134 | " ~~ " => TokenKind::Whitespace, 135 | " ~~~~~~~~ " => TokenKind::IntLiteral, 136 | " ~~" => TokenKind::Whitespace, 137 | }; 138 | } 139 | 140 | #[test] 141 | fn float_literal() { 142 | test! { 143 | " 122.345 1.0 0e1 0E2 0.3e-2_3 0_1.0e_1_ -1.0 ", 144 | "~~ " => TokenKind::Whitespace, 145 | " ~~~~~~~ " => TokenKind::FloatLiteral, 146 | " ~ " => TokenKind::Whitespace, 147 | " ~~~ " => TokenKind::FloatLiteral, 148 | " ~ " => TokenKind::Whitespace, 149 | " ~~~ " => TokenKind::FloatLiteral, 150 | " ~ " => TokenKind::Whitespace, 151 | " ~~~ " => TokenKind::FloatLiteral, 152 | " ~ " => TokenKind::Whitespace, 153 | " ~~~~~~~~ " => TokenKind::FloatLiteral, 154 | " ~ " => TokenKind::Whitespace, 155 | " ~~~~~~~~~ " => TokenKind::FloatLiteral, 156 | " ~ " => TokenKind::Whitespace, 157 | " ~~~~ " => TokenKind::FloatLiteral, 158 | " ~~" => TokenKind::Whitespace, 159 | }; 160 | } 161 | 162 | #[test] 163 | fn keywords() { 164 | test! { 165 | " as case else if import in let record Record then Type where ", 166 | "~~ " => TokenKind::Whitespace, 167 | " ~~ " => TokenKind::Identifier, 168 | " ~ " => TokenKind::Whitespace, 169 | " ~~~~ " => TokenKind::Keyword, 170 | " ~ " => TokenKind::Whitespace, 171 | " ~~~~ " => TokenKind::Keyword, 172 | " ~ " => TokenKind::Whitespace, 173 | " ~~ " => TokenKind::Keyword, 174 | " ~ " => TokenKind::Whitespace, 175 | " ~~~~~~ " => TokenKind::Identifier, 176 | " ~ " => TokenKind::Whitespace, 177 | " ~~ " => TokenKind::Keyword, 178 | " ~ " => TokenKind::Whitespace, 179 | " ~~~ " => TokenKind::Keyword, 180 | " ~ " => TokenKind::Whitespace, 181 | " ~~~~~~ " => TokenKind::Keyword, 182 | " ~ " => TokenKind::Whitespace, 183 | " ~~~~~~ " => TokenKind::Keyword, 184 | " ~ " => TokenKind::Whitespace, 185 | " ~~~~ " => TokenKind::Keyword, 186 | " ~ " => TokenKind::Whitespace, 187 | " ~~~~ " => TokenKind::Keyword, 188 | " ~ " => TokenKind::Whitespace, 189 | " ~~~~~ " => TokenKind::Identifier, 190 | " ~~" => TokenKind::Whitespace, 191 | }; 192 | } 193 | 194 | #[test] 195 | fn symbols() { 196 | test! { 197 | r" \ ^ : , .. = -> => ? ; ", 198 | r"~ " => TokenKind::Whitespace, 199 | r" ~ " => TokenKind::Symbol, 200 | r" ~ " => TokenKind::Whitespace, 201 | r" ~ " => TokenKind::Caret, 202 | r" ~ " => TokenKind::Whitespace, 203 | r" ~ " => TokenKind::Colon, 204 | r" ~ " => TokenKind::Whitespace, 205 | r" ~ " => TokenKind::Comma, 206 | r" ~ " => TokenKind::Whitespace, 207 | r" ~~ " => TokenKind::Symbol, 208 | r" ~ " => TokenKind::Whitespace, 209 | r" ~ " => TokenKind::Equals, 210 | r" ~ " => TokenKind::Whitespace, 211 | r" ~~ " => TokenKind::RArrow, 212 | r" ~ " => TokenKind::Whitespace, 213 | r" ~~ " => TokenKind::RFatArrow, 214 | r" ~ " => TokenKind::Whitespace, 215 | r" ~ " => TokenKind::Question, 216 | r" ~ " => TokenKind::Whitespace, 217 | r" ~ " => TokenKind::Semicolon, 218 | r" ~" => TokenKind::Whitespace, 219 | } 220 | } 221 | 222 | #[test] 223 | fn delimiters() { 224 | test! { 225 | " ( ) { } [ ] ", 226 | "~ " => TokenKind::Whitespace, 227 | " ~ " => TokenKind::Open(DelimKind::Paren), 228 | " ~ " => TokenKind::Whitespace, 229 | " ~ " => TokenKind::Close(DelimKind::Paren), 230 | " ~ " => TokenKind::Whitespace, 231 | " ~ " => TokenKind::Open(DelimKind::Brace), 232 | " ~ " => TokenKind::Whitespace, 233 | " ~ " => TokenKind::Close(DelimKind::Brace), 234 | " ~ " => TokenKind::Whitespace, 235 | " ~ " => TokenKind::Open(DelimKind::Bracket), 236 | " ~ " => TokenKind::Whitespace, 237 | " ~ " => TokenKind::Close(DelimKind::Bracket), 238 | " ~" => TokenKind::Whitespace, 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /crates/mltt-span/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-span" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "Data structures for tracking source positions in the MLTT language" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | language-reporting = { git = "https://github.com/nikomatsakis/language-reporting", branch = "remove-codespan-dep" } 12 | unicode-segmentation = "1.3.0" 13 | pretty_assertions = "0.6" 14 | -------------------------------------------------------------------------------- /crates/mltt-span/src/file.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::ops; 3 | 4 | use crate::{ByteIndex, ColumnIndex, LineIndex, Location, Span}; 5 | 6 | /// A handle that points to a file in the database. 7 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 8 | pub struct FileId(usize); 9 | 10 | impl fmt::Display for FileId { 11 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 12 | write!(f, "#{}", self.0) 13 | } 14 | } 15 | 16 | /// A span in a file. 17 | pub type FileSpan = Span; 18 | 19 | /// The contents of a file that is stored in the database. 20 | #[derive(Debug, Clone)] 21 | pub struct File { 22 | /// The id of the file in the database. 23 | id: FileId, 24 | /// The name of the file. 25 | name: String, 26 | /// The source code of the file. 27 | contents: String, 28 | /// The starting byte indices in the source code. 29 | line_starts: Vec, 30 | } 31 | 32 | impl File { 33 | /// Get the handle that points to this file. 34 | pub fn id(&self) -> FileId { 35 | self.id 36 | } 37 | 38 | /// Get the name of the file. 39 | pub fn name(&self) -> &str { 40 | &self.name 41 | } 42 | 43 | /// Get a slice to the contents of the file. 44 | pub fn contents(&self) -> &str { 45 | &self.contents 46 | } 47 | 48 | /// Get a slice to the line start indices of the file. 49 | pub fn line_starts(&self) -> &[ByteIndex] { 50 | &self.line_starts 51 | } 52 | 53 | /// Get the span of the source of this file. 54 | pub fn span(&self) -> FileSpan { 55 | Span::from_str(self.id(), self.contents()) 56 | } 57 | } 58 | 59 | /// A database of source files. 60 | #[derive(Debug, Clone)] 61 | pub struct Files { 62 | files: Vec, 63 | } 64 | 65 | impl Files { 66 | /// Create a new, empty database. 67 | pub fn new() -> Files { 68 | Files { files: Vec::new() } 69 | } 70 | 71 | /// Add a file to the database, returning the handle that can be used to refer to it again. 72 | pub fn add(&mut self, name: impl Into, contents: impl Into) -> FileId { 73 | let file_id = FileId(self.files.len()); 74 | let contents = contents.into(); 75 | 76 | // Pre-compute the line starting positions 77 | let line_starts = std::iter::once(0) 78 | .chain(contents.match_indices('\n').map(|(i, _)| i + 1)) 79 | .chain(std::iter::once(contents.len())) 80 | .map(ByteIndex::from) 81 | .collect(); 82 | 83 | // Add the file to the database 84 | self.files.push(File { 85 | id: file_id, 86 | name: name.into(), 87 | contents, 88 | line_starts, 89 | }); 90 | 91 | file_id 92 | } 93 | 94 | pub fn byte_index( 95 | &self, 96 | file_id: FileId, 97 | line: impl Into, 98 | column: impl Into, 99 | ) -> Option { 100 | let file = &self[file_id]; 101 | let line = line.into(); 102 | let column = column.into(); 103 | let line_start = *file.line_starts().get(line.to_usize())?; 104 | 105 | Some(column.to_byte_index(file.contents(), line_start)) 106 | } 107 | 108 | pub fn line_span(&self, file_id: FileId, line: impl Into) -> Option { 109 | let file = &self[file_id]; 110 | let line = line.into(); 111 | let line_start = *file.line_starts().get(line.to_usize())?; 112 | let next_line_start = *file.line_starts().get(line.to_usize() + 1)?; 113 | 114 | Some(Span::new(file_id, line_start, next_line_start)) 115 | } 116 | 117 | pub fn location(&self, file_id: FileId, byte: impl Into) -> Option { 118 | let file = &self[file_id]; 119 | let byte = byte.into(); 120 | let line_starts = file.line_starts(); 121 | match line_starts.binary_search(&byte) { 122 | // Found the start of a line 123 | Ok(line) => Some(Location { 124 | line: LineIndex::from(line), 125 | column: ColumnIndex::from(0), 126 | byte, 127 | }), 128 | // Found something in the middle of a line 129 | Err(next_line) => { 130 | let line = LineIndex::from(next_line - 1); 131 | let line_start = line_starts[line.to_usize()]; 132 | let column = ColumnIndex::from_str(file.contents(), line_start, byte)?; 133 | 134 | Some(Location { line, column, byte }) 135 | }, 136 | } 137 | } 138 | 139 | /// Return a slice of the source file, given a span. 140 | pub fn source(&self, span: FileSpan) -> Option<&str> { 141 | let start = span.start().to_usize(); 142 | let end = span.end().to_usize(); 143 | 144 | self[span.source()].contents.get(start..end) 145 | } 146 | } 147 | 148 | impl language_reporting::ReportingFiles for Files { 149 | type Span = FileSpan; 150 | type FileId = FileId; 151 | 152 | fn file_id(&self, span: FileSpan) -> FileId { 153 | span.source() 154 | } 155 | 156 | fn file_name(&self, file_id: FileId) -> language_reporting::FileName { 157 | language_reporting::FileName::Verbatim(self[file_id].name.clone()) 158 | } 159 | 160 | fn byte_span(&self, file_id: FileId, from_index: usize, to_index: usize) -> Option { 161 | let span = Span::new(file_id, from_index, to_index); 162 | if self[file_id].span().contains(span) { 163 | Some(span) 164 | } else { 165 | None 166 | } 167 | } 168 | 169 | fn byte_index(&self, file_id: FileId, line: usize, column: usize) -> Option { 170 | Files::byte_index(self, file_id, line, column).map(ByteIndex::to_usize) 171 | } 172 | 173 | fn line_span(&self, file_id: FileId, line: usize) -> Option { 174 | Files::line_span(self, file_id, line) 175 | } 176 | 177 | fn location(&self, file_id: FileId, index: usize) -> Option { 178 | Files::location(self, file_id, index).map(Location::into) 179 | } 180 | 181 | fn source(&self, span: FileSpan) -> Option { 182 | Files::source(self, span).map(str::to_owned) 183 | } 184 | } 185 | 186 | impl ops::Index for Files { 187 | type Output = File; 188 | 189 | fn index(&self, index: FileId) -> &File { 190 | &self.files[index.0] 191 | } 192 | } 193 | 194 | #[cfg(test)] 195 | mod test { 196 | use pretty_assertions::assert_eq; 197 | 198 | use super::*; 199 | 200 | #[test] 201 | fn line_starts() { 202 | let mut files = Files::new(); 203 | let file_id = files.add("test", "foo\nbar\r\n\nbaz"); 204 | 205 | assert_eq!( 206 | files[file_id].line_starts(), 207 | [ 208 | ByteIndex::from(0), // "foo\n" 209 | ByteIndex::from(4), // "bar\r\n" 210 | ByteIndex::from(9), // "" 211 | ByteIndex::from(10), // "baz" 212 | ByteIndex::from(13), 213 | ], 214 | ); 215 | } 216 | 217 | #[test] 218 | fn location() { 219 | let mut files = Files::new(); 220 | let file_id = files.add("test", "foo\nbar\r\n\nbaz"); 221 | 222 | assert_eq!( 223 | files.location(file_id, 0), 224 | Some(Location { 225 | line: LineIndex::from(0), 226 | column: ColumnIndex::from(0), 227 | byte: ByteIndex::from(0), 228 | }), 229 | ); 230 | 231 | assert_eq!( 232 | files.location(file_id, 7), 233 | Some(Location { 234 | line: LineIndex::from(1), 235 | column: ColumnIndex::from(3), 236 | byte: ByteIndex::from(7), 237 | }), 238 | ); 239 | 240 | assert_eq!( 241 | files.location(file_id, 8), 242 | Some(Location { 243 | line: LineIndex::from(1), 244 | column: ColumnIndex::from(4), 245 | byte: ByteIndex::from(8), 246 | }), 247 | ); 248 | 249 | assert_eq!( 250 | files.location(file_id, 9), 251 | Some(Location { 252 | line: LineIndex::from(2), 253 | column: ColumnIndex::from(0), 254 | byte: ByteIndex::from(9), 255 | }), 256 | ); 257 | 258 | assert_eq!(files.location(file_id, 100), None); 259 | } 260 | 261 | #[test] 262 | fn line_span_sources() { 263 | let mut files = Files::new(); 264 | let file_id = files.add("test", "foo\nbar\r\n\nbaz"); 265 | 266 | let line_sources = (0..5) 267 | .map(|line| { 268 | let line_span = files.line_span(file_id, LineIndex::from(line))?; 269 | files.source(line_span) 270 | }) 271 | .collect::>(); 272 | 273 | assert_eq!( 274 | line_sources, 275 | [ 276 | Some("foo\n"), 277 | Some("bar\r\n"), 278 | Some("\n"), 279 | Some("baz"), 280 | None 281 | ], 282 | ); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /crates/mltt-span/src/index/byte.rs: -------------------------------------------------------------------------------- 1 | use std::ops; 2 | 3 | /// Byte index into a text string 4 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 5 | pub struct ByteIndex(usize); 6 | 7 | impl ByteIndex { 8 | pub fn to_usize(self) -> usize { 9 | self.0 10 | } 11 | } 12 | 13 | impl From for ByteIndex { 14 | fn from(src: usize) -> ByteIndex { 15 | ByteIndex(src) 16 | } 17 | } 18 | 19 | impl ops::Add for ByteIndex { 20 | type Output = ByteIndex; 21 | 22 | fn add(self, other: ByteSize) -> ByteIndex { 23 | ByteIndex::from(self.to_usize() + other.to_usize()) 24 | } 25 | } 26 | 27 | impl ops::AddAssign for ByteIndex { 28 | fn add_assign(&mut self, other: ByteSize) { 29 | self.0 += other.to_usize(); 30 | } 31 | } 32 | 33 | impl ops::Sub for ByteIndex { 34 | type Output = ByteSize; 35 | 36 | fn sub(self, other: ByteIndex) -> ByteSize { 37 | ByteSize::from(self.to_usize() - other.to_usize()) 38 | } 39 | } 40 | 41 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 42 | pub struct ByteSize(usize); 43 | 44 | impl ByteSize { 45 | pub fn from_char_len_utf8(ch: char) -> ByteSize { 46 | ByteSize::from(ch.len_utf8()) 47 | } 48 | 49 | pub fn from_char_len_utf16(ch: char) -> ByteSize { 50 | ByteSize::from(ch.len_utf16()) 51 | } 52 | 53 | pub fn from_str_len_utf8(s: &str) -> ByteSize { 54 | ByteSize::from(s.len()) 55 | } 56 | 57 | pub fn to_usize(self) -> usize { 58 | self.0 59 | } 60 | } 61 | 62 | impl ops::Add for ByteSize { 63 | type Output = ByteSize; 64 | 65 | fn add(self, other: ByteSize) -> ByteSize { 66 | ByteSize::from(self.to_usize() + other.to_usize()) 67 | } 68 | } 69 | 70 | impl ops::AddAssign for ByteSize { 71 | fn add_assign(&mut self, other: ByteSize) { 72 | self.0 += other.to_usize(); 73 | } 74 | } 75 | 76 | impl From for ByteSize { 77 | fn from(src: usize) -> ByteSize { 78 | ByteSize(src) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /crates/mltt-span/src/index/column.rs: -------------------------------------------------------------------------------- 1 | use std::ops; 2 | use unicode_segmentation::UnicodeSegmentation; 3 | 4 | use crate::{ByteIndex, ByteSize}; 5 | 6 | /// 0-based column number, segmented using grapheme clusters 7 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 8 | pub struct ColumnIndex(usize); 9 | 10 | impl ColumnIndex { 11 | pub fn from_str( 12 | src: &str, 13 | line_start_byte: ByteIndex, 14 | column_byte: ByteIndex, 15 | ) -> Option { 16 | let line_src = &src.get(line_start_byte.to_usize()..column_byte.to_usize())?; 17 | Some(ColumnIndex::from(line_src.graphemes(true).count())) 18 | } 19 | 20 | pub fn to_usize(self) -> usize { 21 | self.0 22 | } 23 | 24 | /// Convert to a byte size, based on a unicode string 25 | pub fn to_byte_size(self, line_src: &str) -> ByteSize { 26 | line_src 27 | .graphemes(true) 28 | .map(ByteSize::from_str_len_utf8) 29 | .fold(ByteSize::from(0), |acc, size| acc + size) 30 | } 31 | 32 | /// Convert to a byte index, based on a unicode string and a starting index 33 | pub fn to_byte_index(self, src: &str, line_start_byte: ByteIndex) -> ByteIndex { 34 | line_start_byte + self.to_byte_size(&src[line_start_byte.to_usize()..]) 35 | } 36 | } 37 | 38 | impl From for ColumnIndex { 39 | fn from(src: usize) -> ColumnIndex { 40 | ColumnIndex(src) 41 | } 42 | } 43 | 44 | impl ops::Add for ColumnIndex { 45 | type Output = ColumnIndex; 46 | 47 | fn add(self, other: ColumnSize) -> ColumnIndex { 48 | ColumnIndex::from(self.to_usize() + other.to_usize()) 49 | } 50 | } 51 | 52 | impl ops::AddAssign for ColumnIndex { 53 | fn add_assign(&mut self, other: ColumnSize) { 54 | self.0 += other.to_usize(); 55 | } 56 | } 57 | 58 | impl ops::Sub for ColumnIndex { 59 | type Output = ColumnSize; 60 | 61 | fn sub(self, other: ColumnIndex) -> ColumnSize { 62 | ColumnSize::from(self.to_usize() - other.to_usize()) 63 | } 64 | } 65 | 66 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 67 | pub struct ColumnSize(usize); 68 | 69 | impl ColumnSize { 70 | pub fn to_usize(self) -> usize { 71 | self.0 72 | } 73 | } 74 | 75 | impl From for ColumnSize { 76 | fn from(src: usize) -> ColumnSize { 77 | ColumnSize(src) 78 | } 79 | } 80 | 81 | impl ops::Add for ColumnSize { 82 | type Output = ColumnSize; 83 | 84 | fn add(self, other: ColumnSize) -> ColumnSize { 85 | ColumnSize::from(self.to_usize() + other.to_usize()) 86 | } 87 | } 88 | 89 | impl ops::AddAssign for ColumnSize { 90 | fn add_assign(&mut self, other: ColumnSize) { 91 | self.0 += other.to_usize(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /crates/mltt-span/src/index/line.rs: -------------------------------------------------------------------------------- 1 | use std::ops; 2 | 3 | /// 0-based line number 4 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 5 | pub struct LineIndex(usize); 6 | 7 | impl LineIndex { 8 | pub fn to_usize(self) -> usize { 9 | self.0 10 | } 11 | } 12 | 13 | impl From for LineIndex { 14 | fn from(src: usize) -> LineIndex { 15 | LineIndex(src) 16 | } 17 | } 18 | 19 | impl ops::Add for LineIndex { 20 | type Output = LineIndex; 21 | 22 | fn add(self, other: LineSize) -> LineIndex { 23 | LineIndex::from(self.to_usize() + other.to_usize()) 24 | } 25 | } 26 | 27 | impl ops::AddAssign for LineIndex { 28 | fn add_assign(&mut self, other: LineSize) { 29 | self.0 += other.to_usize(); 30 | } 31 | } 32 | 33 | impl ops::Sub for LineIndex { 34 | type Output = LineSize; 35 | 36 | fn sub(self, other: LineIndex) -> LineSize { 37 | LineSize::from(self.to_usize() - other.to_usize()) 38 | } 39 | } 40 | 41 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 42 | pub struct LineSize(usize); 43 | 44 | impl LineSize { 45 | pub fn to_usize(self) -> usize { 46 | self.0 47 | } 48 | } 49 | 50 | impl ops::Add for LineSize { 51 | type Output = LineSize; 52 | 53 | fn add(self, other: LineSize) -> LineSize { 54 | LineSize::from(self.to_usize() + other.to_usize()) 55 | } 56 | } 57 | 58 | impl ops::AddAssign for LineSize { 59 | fn add_assign(&mut self, other: LineSize) { 60 | self.0 += other.to_usize(); 61 | } 62 | } 63 | 64 | impl From for LineSize { 65 | fn from(src: usize) -> LineSize { 66 | LineSize(src) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /crates/mltt-span/src/index/mod.rs: -------------------------------------------------------------------------------- 1 | mod byte; 2 | mod column; 3 | mod line; 4 | 5 | pub use self::byte::*; 6 | pub use self::column::*; 7 | pub use self::line::*; 8 | -------------------------------------------------------------------------------- /crates/mltt-span/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Data structures for tracking source positions in the MLTT language. 2 | 3 | #![warn(rust_2018_idioms)] 4 | 5 | mod file; 6 | mod index; 7 | mod location; 8 | mod span; 9 | 10 | pub use crate::file::*; 11 | pub use crate::index::*; 12 | pub use crate::location::*; 13 | pub use crate::span::*; 14 | -------------------------------------------------------------------------------- /crates/mltt-span/src/location.rs: -------------------------------------------------------------------------------- 1 | use crate::{ByteIndex, ColumnIndex, LineIndex}; 2 | 3 | /// A location in a source file. 4 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 5 | pub struct Location { 6 | /// The line index in the source file. 7 | pub line: LineIndex, 8 | /// The column index in the source file. 9 | pub column: ColumnIndex, 10 | /// The byte index in the source file. 11 | pub byte: ByteIndex, 12 | } 13 | 14 | impl Into for Location { 15 | fn into(self) -> language_reporting::Location { 16 | language_reporting::Location { 17 | line: self.line.to_usize(), 18 | column: self.column.to_usize(), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/mltt-span/src/span.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::{ByteIndex, ByteSize}; 4 | 5 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 6 | pub struct Span { 7 | source: Source, 8 | start: ByteIndex, 9 | end: ByteIndex, 10 | } 11 | 12 | impl Span { 13 | pub fn new( 14 | source: Source, 15 | start: impl Into, 16 | end: impl Into, 17 | ) -> Span { 18 | let start = start.into(); 19 | let end = end.into(); 20 | 21 | assert!(end >= start); 22 | 23 | Span { source, start, end } 24 | } 25 | 26 | /// Gives an empty span at the start of a source. 27 | pub fn initial(source: Source) -> Span { 28 | Span::new(source, 0, 0) 29 | } 30 | 31 | pub fn from_str(source: Source, s: &str) -> Span { 32 | Span::new(source, 0, s.len()) 33 | } 34 | 35 | pub fn merge(self, other: Span) -> Span { 36 | Span::new(self.source(), self.start(), other.end()) 37 | } 38 | 39 | pub fn with_source(&self, source: NewSource) -> Span { 40 | Span::new(source, self.start(), self.end()) 41 | } 42 | 43 | pub fn with_start(&self, start: impl Into) -> Span { 44 | Span::new(self.source(), start, self.end()) 45 | } 46 | 47 | pub fn with_end(&self, end: impl Into) -> Span { 48 | Span::new(self.source(), self.start(), end) 49 | } 50 | 51 | pub fn start_span(&self) -> Span { 52 | self.with_end(self.start()) 53 | } 54 | 55 | pub fn end_span(&self) -> Span { 56 | self.with_start(self.end()) 57 | } 58 | 59 | pub fn source(&self) -> Source { 60 | self.source 61 | } 62 | 63 | pub fn start(&self) -> ByteIndex { 64 | self.start 65 | } 66 | 67 | pub fn end(&self) -> ByteIndex { 68 | self.end 69 | } 70 | 71 | pub fn contains(self, span: Span) -> bool 72 | where 73 | Source: PartialEq, 74 | { 75 | self.source() == span.source() && self.start() >= span.start() && self.end() < span.end() 76 | } 77 | 78 | pub fn contains_index(self, index: impl Into) -> bool { 79 | let index = index.into(); 80 | self.start() <= index && index < self.end() 81 | } 82 | 83 | pub fn len(&self) -> ByteSize { 84 | self.end() - self.start() 85 | } 86 | } 87 | 88 | impl language_reporting::ReportingSpan for Span { 89 | fn with_start(&self, start: usize) -> Span { 90 | Span::with_start(self, ByteIndex::from(start)) 91 | } 92 | 93 | fn with_end(&self, end: usize) -> Span { 94 | Span::with_end(self, ByteIndex::from(end)) 95 | } 96 | 97 | fn start(&self) -> usize { 98 | Span::start(self).to_usize() 99 | } 100 | 101 | fn end(&self) -> usize { 102 | Span::end(self).to_usize() 103 | } 104 | } 105 | 106 | impl fmt::Debug for Span { 107 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 108 | write!( 109 | f, 110 | "{source:?}:[{start}, {end})", 111 | source = self.source, 112 | start = self.start().to_usize(), 113 | end = self.end().to_usize(), 114 | ) 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /crates/mltt-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mltt-test" 3 | version = "0.1.0" 4 | authors = ["Brendan Zabarauskas "] 5 | description = "Integration tests for the MLTT language" 6 | license = "MIT" 7 | edition = "2018" 8 | publish = false 9 | 10 | [dependencies] 11 | language-reporting = { git = "https://github.com/nikomatsakis/language-reporting", branch = "remove-codespan-dep" } 12 | mltt-concrete = { path = "../mltt-concrete"} 13 | mltt-core = { path = "../mltt-core"} 14 | mltt-elaborate = { path = "../mltt-elaborate"} 15 | mltt-parse = { path = "../mltt-parse"} 16 | mltt-span = { path = "../mltt-span"} 17 | pretty_env_logger = "0.3" 18 | -------------------------------------------------------------------------------- /crates/mltt-test/src/support.rs: -------------------------------------------------------------------------------- 1 | use language_reporting::termcolor::{ColorChoice, StandardStream}; 2 | use language_reporting::Diagnostic; 3 | use mltt_core::{domain, nbe, syntax, validate}; 4 | use mltt_elaborate::MetaInsertion; 5 | use mltt_parse::lexer::Lexer; 6 | use mltt_parse::parser; 7 | use mltt_span::{File, FileId, FileSpan, Files}; 8 | use std::fs; 9 | use std::rc::Rc; 10 | 11 | const TESTS_DIR: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests"); 12 | const REPORTING_CONFIG: language_reporting::DefaultConfig = language_reporting::DefaultConfig; 13 | 14 | fn setup() -> (Files, mltt_core::meta::Env, mltt_elaborate::Context) { 15 | let files = Files::new(); 16 | let metas = mltt_core::meta::Env::new(); 17 | let context = mltt_elaborate::Context::default(); 18 | (files, metas, context) 19 | } 20 | 21 | fn load_file(files: &mut Files, path: String) -> FileId { 22 | let src = fs::read_to_string(&path).unwrap_or_else(|error| panic!("{}", error)); 23 | files.add(path, src) 24 | } 25 | 26 | fn emit_diagnostic<'a, T>( 27 | writer: &'a StandardStream, 28 | files: &'a Files, 29 | ) -> impl FnOnce(Diagnostic) -> T + 'a { 30 | move |diagnostic| { 31 | let writer = &mut writer.lock(); 32 | language_reporting::emit(writer, files, &diagnostic, &REPORTING_CONFIG).unwrap(); 33 | panic!("error encountered"); 34 | } 35 | } 36 | 37 | fn synth_universe( 38 | context: &mltt_elaborate::Context, 39 | metas: &mut mltt_core::meta::Env, 40 | concrete_ty_file: &File, 41 | ) -> Result, Diagnostic> { 42 | let lexer = Lexer::new(&concrete_ty_file); 43 | let concrete_ty = parser::parse_term(lexer)?; 44 | // FIXME: check lexer for errors 45 | 46 | let (ty, level1) = mltt_elaborate::synth_universe(context, metas, &concrete_ty)?; 47 | let level2 = validate::synth_universe(&context.validation_context(), metas, &ty) 48 | .unwrap_or_else(|error| panic!("validation error: {}", error)); 49 | 50 | assert_eq!(level1, level2); 51 | 52 | context.eval_term(metas, concrete_ty.span(), &ty) 53 | } 54 | 55 | fn check_term( 56 | context: &mltt_elaborate::Context, 57 | metas: &mut mltt_core::meta::Env, 58 | concrete_term_file: &File, 59 | expected_ty: &Rc, 60 | ) -> Result, Diagnostic> { 61 | let lexer = Lexer::new(&concrete_term_file); 62 | let concrete_term = parser::parse_term(lexer)?; 63 | // FIXME: check lexer for errors 64 | 65 | let term = mltt_elaborate::check_term(context, metas, &concrete_term, &expected_ty)?; 66 | validate::check_term(&context.validation_context(), &metas, &term, &expected_ty) 67 | .unwrap_or_else(|error| panic!("{}", error)); 68 | 69 | Ok(term) 70 | } 71 | 72 | fn synth_term( 73 | context: &mltt_elaborate::Context, 74 | metas: &mut mltt_core::meta::Env, 75 | concrete_term_file: &File, 76 | expected_ty: &Rc, 77 | ) -> Result<(Rc, Rc), Diagnostic> { 78 | let lexer = Lexer::new(&concrete_term_file); 79 | let concrete_term = parser::parse_term(lexer)?; 80 | // FIXME: check lexer for errors 81 | 82 | let (term, term_ty) = 83 | mltt_elaborate::synth_term(MetaInsertion::Yes, context, metas, &concrete_term)?; 84 | validate::synth_term(&context.validation_context(), &metas, &term) 85 | .unwrap_or_else(|error| panic!("{}", error)); 86 | 87 | // Verify that we got the expected type (sans subtyping) 88 | let prims = context.prims(); 89 | let size = context.values().size(); 90 | if !nbe::check_ty(&prims, &metas, size, false, &term_ty, &expected_ty) 91 | .unwrap_or_else(|error| panic!("{}", error)) 92 | { 93 | panic!("unequal types"); 94 | } 95 | 96 | // Ensure that the checking also works 97 | let term2 = mltt_elaborate::check_term(context, metas, &concrete_term, expected_ty)?; 98 | validate::check_term(&context.validation_context(), &metas, &term2, &expected_ty) 99 | .unwrap_or_else(|error| panic!("{}", error)); 100 | 101 | Ok((term, term_ty)) 102 | } 103 | 104 | pub fn run_sample(name: &str) { 105 | let _ = pretty_env_logger::try_init(); 106 | let writer = StandardStream::stdout(ColorChoice::Always); 107 | 108 | let (mut files, mut metas, context) = setup(); 109 | 110 | let module_path = format!("{}/samples/{}.mltt", TESTS_DIR, name); 111 | let module_file_id = load_file(&mut files, module_path); 112 | 113 | let lexer = Lexer::new(&files[module_file_id]); 114 | let concrete_module = 115 | parser::parse_module(lexer).unwrap_or_else(emit_diagnostic(&writer, &files)); 116 | // FIXME: check lexer for errors 117 | 118 | let module = mltt_elaborate::check_module(&context, &mut metas, &concrete_module) 119 | .unwrap_or_else(emit_diagnostic(&writer, &files)); 120 | validate::check_module(&context.validation_context(), &metas, &module) 121 | .unwrap_or_else(|error| panic!("{}", error)); 122 | } 123 | 124 | pub fn run_elaborate_check_pass(name: &str) { 125 | let _ = pretty_env_logger::try_init(); 126 | let writer = StandardStream::stdout(ColorChoice::Always); 127 | 128 | let (mut files, mut metas, context) = setup(); 129 | 130 | let term_path = format!("{}/elaborate/check-pass/{}.term.mltt", TESTS_DIR, name); 131 | let ty_path = format!("{}/elaborate/check-pass/{}.type.mltt", TESTS_DIR, name); 132 | let term_file_id = load_file(&mut files, term_path); 133 | let ty_file_id = load_file(&mut files, ty_path); 134 | 135 | let expected_ty = synth_universe(&context, &mut metas, &files[ty_file_id]) 136 | .unwrap_or_else(emit_diagnostic(&writer, &files)); 137 | check_term(&context, &mut metas, &files[term_file_id], &expected_ty) 138 | .unwrap_or_else(emit_diagnostic(&writer, &files)); 139 | } 140 | 141 | pub fn run_elaborate_check_fail(name: &str) { 142 | let _ = pretty_env_logger::try_init(); 143 | let writer = StandardStream::stdout(ColorChoice::Always); 144 | 145 | let (mut files, mut metas, context) = setup(); 146 | 147 | let term_path = format!("{}/elaborate/check-fail/{}.term.mltt", TESTS_DIR, name); 148 | let ty_path = format!("{}/elaborate/check-fail/{}.type.mltt", TESTS_DIR, name); 149 | let term_file_id = load_file(&mut files, term_path); 150 | let ty_file_id = load_file(&mut files, ty_path); 151 | 152 | let lexer = Lexer::new(&files[term_file_id]); 153 | let _concrete_term = parser::parse_term(lexer).unwrap_or_else(emit_diagnostic(&writer, &files)); 154 | 155 | let _expected_ty = synth_universe(&context, &mut metas, &files[ty_file_id]) 156 | .unwrap_or_else(emit_diagnostic(&writer, &files)); 157 | // TODO: Check failures 158 | } 159 | 160 | pub fn run_elaborate_synth_pass(name: &str) { 161 | let _ = pretty_env_logger::try_init(); 162 | let writer = StandardStream::stdout(ColorChoice::Always); 163 | 164 | let (mut files, mut metas, context) = setup(); 165 | 166 | let term_path = format!("{}/elaborate/synth-pass/{}.term.mltt", TESTS_DIR, name); 167 | let ty_path = format!("{}/elaborate/synth-pass/{}.type.mltt", TESTS_DIR, name); 168 | let term_file_id = load_file(&mut files, term_path); 169 | let ty_file_id = load_file(&mut files, ty_path); 170 | 171 | let expected_ty = synth_universe(&context, &mut metas, &files[ty_file_id]) 172 | .unwrap_or_else(emit_diagnostic(&writer, &files)); 173 | synth_term(&context, &mut metas, &files[term_file_id], &expected_ty) 174 | .unwrap_or_else(emit_diagnostic(&writer, &files)); 175 | } 176 | 177 | pub fn run_elaborate_synth_fail(name: &str) { 178 | let _ = pretty_env_logger::try_init(); 179 | let writer = StandardStream::stdout(ColorChoice::Always); 180 | 181 | let (mut files, mut _metas, _context) = setup(); 182 | 183 | let term_path = format!("{}/elaborate/synth-fail/{}.term.mltt", TESTS_DIR, name); 184 | let term_file_id = load_file(&mut files, term_path); 185 | 186 | let lexer = Lexer::new(&files[term_file_id]); 187 | let _concrete_term = parser::parse_term(lexer).unwrap_or_else(emit_diagnostic(&writer, &files)); 188 | 189 | // TODO: Check failures 190 | } 191 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | unstable_features = true 2 | match_block_trailing_comma = true 3 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u16/dec-overflow.term.mltt: -------------------------------------------------------------------------------- 1 | 65536 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u16/dec-overflow.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u16/dec-underflow.term.mltt: -------------------------------------------------------------------------------- 1 | -1 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u16/dec-underflow.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u8/dec-overflow.term.mltt: -------------------------------------------------------------------------------- 1 | 256 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u8/dec-overflow.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u8/dec-underflow.term.mltt: -------------------------------------------------------------------------------- 1 | -1 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/literal-intro/int/u8/dec-underflow.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/record-intro/superfluous-field.term.mltt: -------------------------------------------------------------------------------- 1 | record { 2 | x = record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/record-intro/superfluous-field.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/record-intro/unexpected-field.term.mltt: -------------------------------------------------------------------------------- 1 | record { 2 | x = record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-fail/record-intro/unexpected-field.type.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | y : Record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/default-bind.term.mltt: -------------------------------------------------------------------------------- 1 | fun value => case value { 2 | "hi" => "bye"; 3 | other => other; 4 | } 5 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/default-bind.type.mltt: -------------------------------------------------------------------------------- 1 | String -> String 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/default.term.mltt: -------------------------------------------------------------------------------- 1 | fun x => case x { 2 | _ => "default"; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/default.type.mltt: -------------------------------------------------------------------------------- 1 | Bool -> String 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/overlapping.term.mltt: -------------------------------------------------------------------------------- 1 | fun number => case number { 2 | 42 => "forty-two"; 3 | 42 => "42"; 4 | _ => "default"; 5 | } 6 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/overlapping.type.mltt: -------------------------------------------------------------------------------- 1 | U32 -> String 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/simple.term.mltt: -------------------------------------------------------------------------------- 1 | fun magic => case magic { 2 | 7 => "the common choice"; 3 | 42 => "life, the universe, and everything"; 4 | 13 => "unlucky"; 5 | _ => "nonsense"; 6 | } 7 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/case/simple.type.mltt: -------------------------------------------------------------------------------- 1 | U32 -> String 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/fun-intro/explicit.term.mltt: -------------------------------------------------------------------------------- 1 | fun x => x 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/fun-intro/explicit.type.mltt: -------------------------------------------------------------------------------- 1 | Bool -> Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/fun-intro/implicit.term.mltt: -------------------------------------------------------------------------------- 1 | fun {A} => A 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/fun-intro/implicit.type.mltt: -------------------------------------------------------------------------------- 1 | Fun {A : Type} -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/fun-intro/instance.term.mltt: -------------------------------------------------------------------------------- 1 | fun {{A}} => A 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/fun-intro/instance.type.mltt: -------------------------------------------------------------------------------- 1 | Fun {{A : Type}} -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/if.term.mltt: -------------------------------------------------------------------------------- 1 | if true then 2 | false 3 | else 4 | true 5 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/if.type.mltt: -------------------------------------------------------------------------------- 1 | Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b111111111111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0b1000000000000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 32767 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | -32768 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0x7fff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0x8000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o77777 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0o100000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s16/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b1111111111111111111111111111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0b10000000000000000000000000000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 2147483647 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | -2147483648 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0x7fffffff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0x80000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o17777777777 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0o20000000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s32/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b111111111111111111111111111111111111111111111111111111111111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0b1000000000000000000000000000000000000000000000000000000000000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 9223372036854775807 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | -9223372036854775808 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0x7fffffffffffffff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0x8000000000000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o777777777777777777777 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0o1000000000000000000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s64/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b1111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0b10000000 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 127 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | -128 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0x7f 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0x80 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o177 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | -0o200 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/s8/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b1111111111111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0b0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 65535 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0xffff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0x0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o177777 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0o0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u16/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b11111111111111111111111111111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0b0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 4294967295 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0xffffffff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0x0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o37777777777 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0o0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u32/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b1111111111111111111111111111111111111111111111111111111111111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0b0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 18446744073709551615 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0xffffffffffffffff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0x0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o1777777777777777777777 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0o0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u64/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/bin-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0b11111111 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/bin-max.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/bin-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0b0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/bin-min.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/dec-max.term.mltt: -------------------------------------------------------------------------------- 1 | 255 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/dec-max.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/dec-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/dec-min.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/hex-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0xff 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/hex-max.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/hex-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0x0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/hex-min.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/oct-max.term.mltt: -------------------------------------------------------------------------------- 1 | 0o377 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/oct-max.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/oct-min.term.mltt: -------------------------------------------------------------------------------- 1 | 0o0 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/oct-min.type.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/samples.term.mltt: -------------------------------------------------------------------------------- 1 | -- TODO: Split into separate tests 2 | let 3 | bin-0 : U8 = 0b0; 4 | bin-1 : U8 = 0b1; 5 | bin-11 : U8 = 0b11; 6 | bin-11-11 : U8 = 0b_11_11; 7 | oct-172 : U8 = 0o___172; 8 | dec-0 : U8 = 0; 9 | dec-0000 : U8 = 0000; 10 | dec-0--12 : U8 = 0__12; 11 | hex-a : U8 = 0xA; 12 | in 13 | record {} 14 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/literal-intro/int/u8/samples.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/parens.term.mltt: -------------------------------------------------------------------------------- 1 | (fun x => x) 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/parens.type.mltt: -------------------------------------------------------------------------------- 1 | Type -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/prim.term.mltt: -------------------------------------------------------------------------------- 1 | primitive "u8-add" 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/prim.type.mltt: -------------------------------------------------------------------------------- 1 | U8 -> U8 -> U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/record-intro/dependent-pair.term.mltt: -------------------------------------------------------------------------------- 1 | record { 2 | Unit = Record {}; 3 | unit = record {}; 4 | } 5 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/record-intro/dependent-pair.type.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | Unit : Type; 3 | unit : Unit; 4 | } 5 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/record-intro/singleton.term.mltt: -------------------------------------------------------------------------------- 1 | record { 2 | unit = record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/record-intro/singleton.type.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | unit : Record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/record-intro/singleton1.term.mltt: -------------------------------------------------------------------------------- 1 | record { 2 | Unit = Record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/check-pass/record-intro/singleton1.type.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | Unit : Type; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/fun-intro/ambiguous.term.mltt: -------------------------------------------------------------------------------- 1 | fun x => x 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/hole/ambiguous.term.mltt: -------------------------------------------------------------------------------- 1 | ? 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/let/already-defined.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | Unit : Type; 3 | Unit = Record {}; 4 | Unit = Record {}; 5 | in 6 | Unit 7 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/let/not-yet-declared.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | Unit : Type; 3 | 4 | foo : Type -> Unit; 5 | 6 | Unit = Record {}; 7 | 8 | unit : Unit; 9 | unit = record {}; 10 | 11 | foo A = unit; 12 | in 13 | foo 14 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/literal-intro/float/ambiguous.term.mltt: -------------------------------------------------------------------------------- 1 | 0.0 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/literal-intro/int/ambiguous.term.mltt: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/prim/ambiguous.term.mltt: -------------------------------------------------------------------------------- 1 | primitive "abort" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/prim/unknown.term.mltt: -------------------------------------------------------------------------------- 1 | primitive "foo" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/record-elim/field-not-found.term.mltt: -------------------------------------------------------------------------------- 1 | (record {}).foo 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/record-intro/ambiguous.term.mltt: -------------------------------------------------------------------------------- 1 | record { 2 | x = record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/universe/overflow.term.mltt: -------------------------------------------------------------------------------- 1 | Type^65535 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-fail/var/unbound.term.mltt: -------------------------------------------------------------------------------- 1 | free 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/explicit.term.mltt: -------------------------------------------------------------------------------- 1 | ((fun x => x) : Bool -> Bool) true 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/explicit.type.mltt: -------------------------------------------------------------------------------- 1 | Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/implicit-insert-meta.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | id : Fun {A : Type} -> A -> A; 3 | id a = a; 4 | in 5 | id true 6 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/implicit-insert-meta.type.mltt: -------------------------------------------------------------------------------- 1 | Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/implicit.term.mltt: -------------------------------------------------------------------------------- 1 | ((fun {A} => A) : Fun {A : Type} -> Type) {A = Bool} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/implicit.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/instance.term.mltt: -------------------------------------------------------------------------------- 1 | ((fun {{A}} => A) : Fun {{A : Type}} -> Type) {{A = Bool}} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-elim/instance.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/term-term.term.mltt: -------------------------------------------------------------------------------- 1 | Bool -> Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/term-term.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/term-type.term.mltt: -------------------------------------------------------------------------------- 1 | Bool -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/term-type.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/term-type1.term.mltt: -------------------------------------------------------------------------------- 1 | Bool -> Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/term-type1.type.mltt: -------------------------------------------------------------------------------- 1 | Type^2 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/type-term.term.mltt: -------------------------------------------------------------------------------- 1 | Type -> Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/type-term.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/type-type.term.mltt: -------------------------------------------------------------------------------- 1 | Type -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/type-type.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/type1-term.term.mltt: -------------------------------------------------------------------------------- 1 | Type^1 -> Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type-arrow/type1-term.type.mltt: -------------------------------------------------------------------------------- 1 | Type^2 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type/param-group-1.term.mltt: -------------------------------------------------------------------------------- 1 | Fun (A : Type) (B : Type) -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type/param-group-1.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type/param-group-2.term.mltt: -------------------------------------------------------------------------------- 1 | Fun (A B : Type) -> Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/fun-type/param-group-2.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/complicated.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | Unit = Record {}; 3 | 4 | unit : Unit; 5 | unit = record {}; 6 | 7 | -- The core syntax of this let binding should only be typeable 8 | -- if we have annotations in the core syntax. 9 | id : Fun {A : Type} -> A -> A; 10 | id {A} a = a; 11 | in 12 | id {A = Unit} unit 13 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/complicated.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/declaration-definition.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | Unit : Type; 3 | Unit = Record {}; 4 | in 5 | Unit 6 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/declaration-definition.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/definition.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | Unit = Record {}; 3 | in 4 | Unit 5 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/definition.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/forward-declarations.term.mltt: -------------------------------------------------------------------------------- 1 | let 2 | Unit : Type; 3 | Unit = Record {}; 4 | 5 | foo : Type -> Unit; 6 | 7 | unit : Unit; 8 | unit = record {}; 9 | 10 | foo A = unit; 11 | in 12 | foo 13 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/let/forward-declarations.type.mltt: -------------------------------------------------------------------------------- 1 | Type -> Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/ascii.term.mltt: -------------------------------------------------------------------------------- 1 | 'a' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/ascii.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-ascii-lower-max.term.mltt: -------------------------------------------------------------------------------- 1 | '\x7f' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-ascii-lower-max.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-ascii-upper-max.term.mltt: -------------------------------------------------------------------------------- 1 | '\x7F' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-ascii-upper-max.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-back-slash.term.mltt: -------------------------------------------------------------------------------- 1 | '\\' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-back-slash.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-carriage-return.term.mltt: -------------------------------------------------------------------------------- 1 | '\r' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-carriage-return.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-double-quote.term.mltt: -------------------------------------------------------------------------------- 1 | '\"' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-double-quote.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-new-line.term.mltt: -------------------------------------------------------------------------------- 1 | '\n' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-new-line.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-null.term.mltt: -------------------------------------------------------------------------------- 1 | '\0' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-null.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-single-quote.term.mltt: -------------------------------------------------------------------------------- 1 | '\'' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-single-quote.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-tab.term.mltt: -------------------------------------------------------------------------------- 1 | '\t' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-simple-tab.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-unicode-lower-max.term.mltt: -------------------------------------------------------------------------------- 1 | '\u{7fff}' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-unicode-lower-max.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-unicode-upper-max.term.mltt: -------------------------------------------------------------------------------- 1 | '\u{7FFF}' 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/char/escape-unicode-upper-max.type.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/ascii.term.mltt: -------------------------------------------------------------------------------- 1 | "Hello world!" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/ascii.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-ascii-lower-max.term.mltt: -------------------------------------------------------------------------------- 1 | "\x7f" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-ascii-lower-max.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-ascii-upper-max.term.mltt: -------------------------------------------------------------------------------- 1 | "\x7F" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-ascii-upper-max.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-back-slash.term.mltt: -------------------------------------------------------------------------------- 1 | "\\" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-back-slash.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-carriage-return.term.mltt: -------------------------------------------------------------------------------- 1 | "\r" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-carriage-return.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-double-quote.term.mltt: -------------------------------------------------------------------------------- 1 | "\"" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-double-quote.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-new-line.term.mltt: -------------------------------------------------------------------------------- 1 | "\n" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-new-line.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-null.term.mltt: -------------------------------------------------------------------------------- 1 | "\0" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-null.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-single-quote.term.mltt: -------------------------------------------------------------------------------- 1 | "\'" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-single-quote.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-tab.term.mltt: -------------------------------------------------------------------------------- 1 | "\t" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-simple-tab.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-unicode-lower-max.term.mltt: -------------------------------------------------------------------------------- 1 | "\u{7fff}" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-unicode-lower-max.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-unicode-upper-max.term.mltt: -------------------------------------------------------------------------------- 1 | "\u{7FFF}" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escape-unicode-upper-max.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escapes.term.mltt: -------------------------------------------------------------------------------- 1 | "\x7f\x7F\u{7fff}\u{7FFF}\'\"\\\n\r\t\0" 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/literal-intro/string/escapes.type.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/parens.term.mltt: -------------------------------------------------------------------------------- 1 | (record {}) 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/parens.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-elim/dependent-pair.term.mltt: -------------------------------------------------------------------------------- 1 | ( 2 | record { 3 | Unit = Record {}; 4 | unit = record {}; 5 | } : Record { 6 | Unit : Type; 7 | unit : Unit; 8 | } 9 | ).unit 10 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-elim/dependent-pair.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-elim/singleton.term.mltt: -------------------------------------------------------------------------------- 1 | ( 2 | record { 3 | unit = record {}; 4 | } : Record { 5 | unit : Record {}; 6 | } 7 | ).unit 8 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-elim/singleton.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-intro/empty.term.mltt: -------------------------------------------------------------------------------- 1 | record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-intro/empty.type.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/dependent-pair.term.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | Unit : Type; 3 | unit : Unit; 4 | } 5 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/dependent-pair.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/empty.term.mltt: -------------------------------------------------------------------------------- 1 | Record {} 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/empty.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/singleton.term.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | unit : Record {}; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/singleton.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/singleton1.term.mltt: -------------------------------------------------------------------------------- 1 | Record { 2 | type : Type; 3 | } 4 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/record-type/singleton1.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/universe/type.term.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/universe/type.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/universe/type0.term.mltt: -------------------------------------------------------------------------------- 1 | Type^0 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/universe/type0.type.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/universe/type1.term.mltt: -------------------------------------------------------------------------------- 1 | Type^1 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/universe/type1.type.mltt: -------------------------------------------------------------------------------- 1 | Type^2 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/bool.term.mltt: -------------------------------------------------------------------------------- 1 | Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/bool.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/char.term.mltt: -------------------------------------------------------------------------------- 1 | Char 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/char.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/f32.term.mltt: -------------------------------------------------------------------------------- 1 | F32 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/f32.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/f64.term.mltt: -------------------------------------------------------------------------------- 1 | F64 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/f64.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/false.term.mltt: -------------------------------------------------------------------------------- 1 | false 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/false.type.mltt: -------------------------------------------------------------------------------- 1 | Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s16.term.mltt: -------------------------------------------------------------------------------- 1 | S16 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s16.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s32.term.mltt: -------------------------------------------------------------------------------- 1 | S32 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s32.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s64.term.mltt: -------------------------------------------------------------------------------- 1 | S64 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s64.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s8.term.mltt: -------------------------------------------------------------------------------- 1 | S8 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/s8.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/string.term.mltt: -------------------------------------------------------------------------------- 1 | String 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/string.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/true.term.mltt: -------------------------------------------------------------------------------- 1 | true 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/true.type.mltt: -------------------------------------------------------------------------------- 1 | Bool 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u16.term.mltt: -------------------------------------------------------------------------------- 1 | U16 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u16.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u32.term.mltt: -------------------------------------------------------------------------------- 1 | U32 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u32.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u64.term.mltt: -------------------------------------------------------------------------------- 1 | U64 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u64.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u8.term.mltt: -------------------------------------------------------------------------------- 1 | U8 2 | -------------------------------------------------------------------------------- /tests/elaborate/synth-pass/var/u8.type.mltt: -------------------------------------------------------------------------------- 1 | Type 2 | -------------------------------------------------------------------------------- /tests/samples/categories.mltt: -------------------------------------------------------------------------------- 1 | ||| A category is a very general structure that provides a common way of composing 2 | ||| units of functionality 3 | ||| 4 | ||| The most common category programmers would be familiar with would be `Type`s 5 | ||| are the objects, and the functions between those types are the arrows. Many 6 | ||| other categories exist though, for example: 7 | ||| 8 | ||| - nodes in a directed graph, and the edges between those nodes. 9 | ||| - etc. 10 | Category = Record { 11 | ||| An object in the category 12 | Object : Type; 13 | ||| Arrows between the objects in the category 14 | Arrow : Object -> Object -> Type; 15 | 16 | ||| The identity arrow 17 | id : Fun {A : Object} -> Arrow A A; 18 | ||| The sequencing of two arrows 19 | seq : Fun {A B C : Object} -> Arrow A B -> Arrow B C -> Arrow A C; 20 | }; 21 | 22 | ||| The identity arrow 23 | id : Fun {{cat : Category}} {A : cat.Object} -> cat.Arrow A A; 24 | id {{cat}} {A} = cat.id {A}; -- FIXME: Extra annotations? 25 | 26 | ||| The sequencing of two arrows 27 | seq : Fun {{cat : Category}} {A B C : cat.Object} -> cat.Arrow A B -> cat.Arrow B C -> cat.Arrow A C; 28 | seq {{cat}} {A} {B} {C} = cat.seq {A} {B} {C}; -- FIXME: Extra annotations? 29 | 30 | ||| The composition of two arrows 31 | compose : Fun {{cat : Category}} {A B C : cat.Object} -> cat.Arrow B C -> cat.Arrow A B -> cat.Arrow A C; 32 | compose {{cat}} {A} {B} {C} f g = seq {{cat}} {A} {B} {C} g f; 33 | 34 | ||| Provides a mapping from objects-to-objects and arrows-to-arrows for two 35 | ||| categories, `Source` and `Target` 36 | ||| 37 | ||| Mappings can be anything from applying a function to each element of a 38 | ||| collection, to compiling a source language to a target language. 39 | ||| 40 | ||| Haskell programmers might find this definition a little foreign - this 41 | ||| is because we use general categories in the definition, rather than 42 | ||| specializing it into the category of Pikelet functions 43 | Functor = Record { 44 | ||| The source category 45 | Source : Category; 46 | ||| The target category 47 | Target : Category; 48 | ||| Maps an object in `Source` to an object in `Target` 49 | Map : Source.Object -> Target.Object; 50 | 51 | ||| Maps an arrow in `Source` into an arrow in `Target` 52 | map : Fun {A B : Source.Object} -> Source.Arrow A B -> Target.Arrow (Map A) (Map B); 53 | }; 54 | 55 | ||| Maps an arrow in `F.Source` into an arrow in `F.Target` 56 | map : 57 | Fun {{functor : Functor}} {A B : functor.Source.Object} -> 58 | functor.Source.Arrow A B -> 59 | functor.Target.Arrow (functor.Map A) (functor.Map B); 60 | map {{functor}} {A} {B} = functor.map {A} {B}; -- FIXME: Extra annotations? 61 | -------------------------------------------------------------------------------- /tests/samples/combinators.mltt: -------------------------------------------------------------------------------- 1 | ||| The unit type 2 | ||| 3 | ||| This is named 'unit' because it only has one possible inhabitant, `unit`. 4 | Unit : Type; 5 | Unit = Record {}; 6 | 7 | ||| Construct a value of the unit type. 8 | unit : Unit; 9 | unit = record {}; 10 | 11 | 12 | ||| The polymorphic identity function 13 | id : Fun {A : Type} -> A -> A; 14 | id a = a; 15 | 16 | test-id : Unit; 17 | test-id = id {A = Unit} unit; 18 | 19 | test-id-holes : Unit; 20 | test-id-holes = id {A = ?} unit; 21 | 22 | test-id-implicit : Unit; 23 | test-id-implicit = id unit; 24 | 25 | 26 | ||| Creates a function that always returns the same value. 27 | ||| 28 | ||| Also known at the 'K Combinator' in the [SKI combinator calculus][ski-wiki]. 29 | ||| 30 | ||| [ski-wiki]: https://en.wikipedia.org/wiki/SKI_combinator_calculus 31 | const : Fun {A B : Type} -> A -> B -> A; 32 | const a = 33 | fun b => a; 34 | 35 | test-const : Unit; 36 | test-const = const {A = Unit} {B = String -> String} unit (id {A = String}); 37 | 38 | test-const-holes : Unit; 39 | test-const-holes = const {A = ?} {B = ?} unit (id {A = String}); 40 | 41 | test-const-implicit : Unit; 42 | test-const-implicit = const unit (id {A = String}); 43 | 44 | 45 | ||| Dependent substitution. 46 | ||| 47 | ||| Takes three arguments and then returns the first argument applied to the 48 | ||| third, which is then applied to the result of the second argument applied to 49 | ||| the third. 50 | ||| 51 | ||| Also known as the 'S Combinator' in the [SKI combinator calculus][ski-wiki]. 52 | ||| 53 | ||| # References 54 | ||| 55 | ||| - [Outrageous but Meaningful Coincidences: Dependent type-safe syntax and evaluation][dep-rep] 56 | ||| (Described in Section 5 as an infix `_ˢ_` operator) 57 | ||| 58 | ||| [ski-wiki]: https://en.wikipedia.org/wiki/SKI_combinator_calculus 59 | ||| [dep-rep]: https://personal.cis.strath.ac.uk/conor.mcbride/pub/DepRep/DepRep.pdf 60 | d-subst : 61 | Fun {A : Type} {B : A -> Type} {C : Fun (a : A) -> B a -> Type} 62 | (f : Fun (a : A) (b : B a) -> C a b) 63 | (g : Fun (a : A) -> B a) -> 64 | (Fun (a : A) -> C a (g a)); 65 | d-subst f g = 66 | fun a => f a (g a); 67 | 68 | ||| Substitution 69 | subst : Fun {A B C : Type} -> (A -> B -> C) -> (A -> B) -> (A -> C); 70 | subst {A} {B} {C} f g = 71 | d-subst {A} {B = fun a => B} {C = fun a b => C} f g; 72 | 73 | 74 | ||| Dependent function composition 75 | d-compose : 76 | Fun {A : Type} {B : A -> Type} {C : Fun {a : A} -> B a -> Type} 77 | (f : Fun {a : A} (b : B a) -> C {a} b) 78 | (g : Fun (a : A) -> B a) -> 79 | (Fun (a : A) -> C {a} (g a)); 80 | d-compose f g = 81 | fun a => f {a} (g a); 82 | 83 | ||| Function composition 84 | compose : Fun {A B C : Type} -> (B -> C) -> (A -> B) -> (A -> C); 85 | compose {A} {B} {C} f g = 86 | d-compose {A} {B = fun a => B} {C = fun {a} b => C} (fun {a} b => f b) g; 87 | 88 | 89 | ||| Flip the order of the first two arguments to a dependent function 90 | d-flip : 91 | Fun {A B : Type} {C : A -> B -> Type} -> 92 | (Fun (a : A) (b : B) -> C a b) -> 93 | (Fun (b : B) (a : A) -> C a b); 94 | d-flip f = 95 | fun a b => f b a; 96 | 97 | ||| Flip the order of the first two arguments to a function 98 | flip : Fun {A B C : Type} -> (A -> B -> C) -> (B -> A -> C); 99 | flip {A} {B} {C} f = 100 | d-flip {A = A} {B = B} {C = fun a b => C} f; 101 | 102 | test-flip : (Unit -> Unit) -> Unit -> Unit; 103 | test-flip = flip {A = Unit} {B = Unit -> Unit} {C = Unit} (const {A = Unit} {B = Unit -> Unit}); 104 | 105 | test-flip-holes : (Unit -> Unit) -> Unit -> Unit; 106 | test-flip-holes = flip {A = ?} {B = ?} {C = ?} (const {A = ?} {B = ?}); 107 | 108 | test-flip-implicit : (Unit -> Unit) -> Unit -> Unit; 109 | test-flip-implicit = flip const; 110 | -------------------------------------------------------------------------------- /tests/samples/connectives.mltt: -------------------------------------------------------------------------------- 1 | ||| Dependent products 2 | Prod : Fun (A : Type) (B : A -> Type) -> Type; 3 | Prod A B = Fun (a : A) -> B a; 4 | 5 | ||| Dependent sums (subtypes) 6 | Sum : Fun (A : Type) (B : A -> Type) -> Type; 7 | Sum A B = Record { 8 | val : A; 9 | proof : B val; 10 | }; 11 | -------------------------------------------------------------------------------- /tests/samples/cumulativity.mltt: -------------------------------------------------------------------------------- 1 | test : Type^1; 2 | test = Type; 3 | 4 | test0 : Type^1; 5 | test0 = Type^0; 6 | 7 | test-levels : Type^1 : Type^2 : Type^3 : Type^23; 8 | test-levels = Type^0; 9 | 10 | test-fun-type : Type^2; 11 | test-fun-type = Type^1 -> Type^0; 12 | 13 | test-fun-intro-a : Type^0 -> Type^1; 14 | test-fun-intro-a x = x; 15 | 16 | test-fun-intro : Type^0 -> Type^2; 17 | test-fun-intro = test-fun-intro-a; 18 | 19 | test-record-intro-a : Record { x : Type^1; y : Type^1 }; 20 | test-record-intro-a = record { x = Type^0; y = Type^0 }; 21 | 22 | test-record-intro : Record { x : Type^2; y : Type^2 }; 23 | test-record-intro = test-record-intro-a; 24 | -------------------------------------------------------------------------------- /tests/samples/empty.mltt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brendanzab/rust-nbe-for-mltt/30dfbb4f2730608c966088de6aacc1074f57e479/tests/samples/empty.mltt -------------------------------------------------------------------------------- /tests/samples/primitives.mltt: -------------------------------------------------------------------------------- 1 | abort : Fun {A : Type} -> String -> A; 2 | abort {A = _} = primitive "abort"; 3 | 4 | string-eq = primitive "string-eq" : String -> String -> Bool; 5 | char-eq = primitive "char-eq" : Char -> Char -> Bool; 6 | u8-eq = primitive "u8-eq" : U8 -> U8 -> Bool; 7 | u16-eq = primitive "u16-eq" : U16 -> U16 -> Bool; 8 | u32-eq = primitive "u32-eq" : U32 -> U32 -> Bool; 9 | u64-eq = primitive "u64-eq" : U64 -> U64 -> Bool; 10 | s8-eq = primitive "s8-eq" : S8 -> S8 -> Bool; 11 | s16-eq = primitive "s16-eq" : S16 -> S16 -> Bool; 12 | s32-eq = primitive "s32-eq" : S32 -> S32 -> Bool; 13 | s64-eq = primitive "s64-eq" : S64 -> S64 -> Bool; 14 | f32-eq = primitive "f32-eq" : F32 -> F32 -> Bool; 15 | f64-eq = primitive "f64-eq" : F64 -> F64 -> Bool; 16 | 17 | string-ne = primitive "string-ne" : String -> String -> Bool; 18 | char-ne = primitive "char-ne" : Char -> Char -> Bool; 19 | u8-ne = primitive "u8-ne" : U8 -> U8 -> Bool; 20 | u16-ne = primitive "u16-ne" : U16 -> U16 -> Bool; 21 | u32-ne = primitive "u32-ne" : U32 -> U32 -> Bool; 22 | u64-ne = primitive "u64-ne" : U64 -> U64 -> Bool; 23 | s8-ne = primitive "s8-ne" : S8 -> S8 -> Bool; 24 | s16-ne = primitive "s16-ne" : S16 -> S16 -> Bool; 25 | s32-ne = primitive "s32-ne" : S32 -> S32 -> Bool; 26 | s64-ne = primitive "s64-ne" : S64 -> S64 -> Bool; 27 | f32-ne = primitive "f32-ne" : F32 -> F32 -> Bool; 28 | f64-ne = primitive "f64-ne" : F64 -> F64 -> Bool; 29 | 30 | string-lt = primitive "string-lt" : String -> String -> Bool; 31 | char-lt = primitive "char-lt" : Char -> Char -> Bool; 32 | u8-lt = primitive "u8-lt" : U8 -> U8 -> Bool; 33 | u16-lt = primitive "u16-lt" : U16 -> U16 -> Bool; 34 | u32-lt = primitive "u32-lt" : U32 -> U32 -> Bool; 35 | u64-lt = primitive "u64-lt" : U64 -> U64 -> Bool; 36 | s8-lt = primitive "s8-lt" : S8 -> S8 -> Bool; 37 | s16-lt = primitive "s16-lt" : S16 -> S16 -> Bool; 38 | s32-lt = primitive "s32-lt" : S32 -> S32 -> Bool; 39 | s64-lt = primitive "s64-lt" : S64 -> S64 -> Bool; 40 | f32-lt = primitive "f32-lt" : F32 -> F32 -> Bool; 41 | f64-lt = primitive "f64-lt" : F64 -> F64 -> Bool; 42 | 43 | string-le = primitive "string-le" : String -> String -> Bool; 44 | char-le = primitive "char-le" : Char -> Char -> Bool; 45 | u8-le = primitive "u8-le" : U8 -> U8 -> Bool; 46 | u16-le = primitive "u16-le" : U16 -> U16 -> Bool; 47 | u32-le = primitive "u32-le" : U32 -> U32 -> Bool; 48 | u64-le = primitive "u64-le" : U64 -> U64 -> Bool; 49 | s8-le = primitive "s8-le" : S8 -> S8 -> Bool; 50 | s16-le = primitive "s16-le" : S16 -> S16 -> Bool; 51 | s32-le = primitive "s32-le" : S32 -> S32 -> Bool; 52 | s64-le = primitive "s64-le" : S64 -> S64 -> Bool; 53 | f32-le = primitive "f32-le" : F32 -> F32 -> Bool; 54 | f64-le = primitive "f64-le" : F64 -> F64 -> Bool; 55 | 56 | string-ge = primitive "string-ge" : String -> String -> Bool; 57 | char-ge = primitive "char-ge" : Char -> Char -> Bool; 58 | u8-ge = primitive "u8-ge" : U8 -> U8 -> Bool; 59 | u16-ge = primitive "u16-ge" : U16 -> U16 -> Bool; 60 | u32-ge = primitive "u32-ge" : U32 -> U32 -> Bool; 61 | u64-ge = primitive "u64-ge" : U64 -> U64 -> Bool; 62 | s8-ge = primitive "s8-ge" : S8 -> S8 -> Bool; 63 | s16-ge = primitive "s16-ge" : S16 -> S16 -> Bool; 64 | s32-ge = primitive "s32-ge" : S32 -> S32 -> Bool; 65 | s64-ge = primitive "s64-ge" : S64 -> S64 -> Bool; 66 | f32-ge = primitive "f32-ge" : F32 -> F32 -> Bool; 67 | f64-ge = primitive "f64-ge" : F64 -> F64 -> Bool; 68 | 69 | string-gt = primitive "string-gt" : String -> String -> Bool; 70 | char-gt = primitive "char-gt" : Char -> Char -> Bool; 71 | u8-gt = primitive "u8-gt" : U8 -> U8 -> Bool; 72 | u16-gt = primitive "u16-gt" : U16 -> U16 -> Bool; 73 | u32-gt = primitive "u32-gt" : U32 -> U32 -> Bool; 74 | u64-gt = primitive "u64-gt" : U64 -> U64 -> Bool; 75 | s8-gt = primitive "s8-gt" : S8 -> S8 -> Bool; 76 | s16-gt = primitive "s16-gt" : S16 -> S16 -> Bool; 77 | s32-gt = primitive "s32-gt" : S32 -> S32 -> Bool; 78 | s64-gt = primitive "s64-gt" : S64 -> S64 -> Bool; 79 | f32-gt = primitive "f32-gt" : F32 -> F32 -> Bool; 80 | f64-gt = primitive "f64-gt" : F64 -> F64 -> Bool; 81 | 82 | u8-add = primitive "u8-add" : U8 -> U8 -> U8; 83 | u16-add = primitive "u16-add" : U16 -> U16 -> U16; 84 | u32-add = primitive "u32-add" : U32 -> U32 -> U32; 85 | u64-add = primitive "u64-add" : U64 -> U64 -> U64; 86 | s8-add = primitive "s8-add" : S8 -> S8 -> S8; 87 | s16-add = primitive "s16-add" : S16 -> S16 -> S16; 88 | s32-add = primitive "s32-add" : S32 -> S32 -> S32; 89 | s64-add = primitive "s64-add" : S64 -> S64 -> S64; 90 | f32-add = primitive "f32-add" : F32 -> F32 -> F32; 91 | f64-add = primitive "f64-add" : F64 -> F64 -> F64; 92 | 93 | u8-sub = primitive "u8-sub" : U8 -> U8 -> U8; 94 | u16-sub = primitive "u16-sub" : U16 -> U16 -> U16; 95 | u32-sub = primitive "u32-sub" : U32 -> U32 -> U32; 96 | u64-sub = primitive "u64-sub" : U64 -> U64 -> U64; 97 | s8-sub = primitive "s8-sub" : S8 -> S8 -> S8; 98 | s16-sub = primitive "s16-sub" : S16 -> S16 -> S16; 99 | s32-sub = primitive "s32-sub" : S32 -> S32 -> S32; 100 | s64-sub = primitive "s64-sub" : S64 -> S64 -> S64; 101 | f32-sub = primitive "f32-sub" : F32 -> F32 -> F32; 102 | f64-sub = primitive "f64-sub" : F64 -> F64 -> F64; 103 | 104 | s8-neg = primitive "s8-neg" : S8 -> S8; 105 | s16-neg = primitive "s16-neg" : S16 -> S16; 106 | s32-neg = primitive "s32-neg" : S32 -> S32; 107 | s64-neg = primitive "s64-neg" : S64 -> S64; 108 | f32-neg = primitive "f32-neg" : F32 -> F32; 109 | f64-neg = primitive "f64-neg" : F64 -> F64; 110 | 111 | u8-mul = primitive "u8-mul" : U8 -> U8 -> U8; 112 | u16-mul = primitive "u16-mul" : U16 -> U16 -> U16; 113 | u32-mul = primitive "u32-mul" : U32 -> U32 -> U32; 114 | u64-mul = primitive "u64-mul" : U64 -> U64 -> U64; 115 | s8-mul = primitive "s8-mul" : S8 -> S8 -> S8; 116 | s16-mul = primitive "s16-mul" : S16 -> S16 -> S16; 117 | s32-mul = primitive "s32-mul" : S32 -> S32 -> S32; 118 | s64-mul = primitive "s64-mul" : S64 -> S64 -> S64; 119 | f32-mul = primitive "f32-mul" : F32 -> F32 -> F32; 120 | f64-mul = primitive "f64-mul" : F64 -> F64 -> F64; 121 | 122 | u8-div = primitive "u8-div" : U8 -> U8 -> U8; 123 | u16-div = primitive "u16-div" : U16 -> U16 -> U16; 124 | u32-div = primitive "u32-div" : U32 -> U32 -> U32; 125 | u64-div = primitive "u64-div" : U64 -> U64 -> U64; 126 | s8-div = primitive "s8-div" : S8 -> S8 -> S8; 127 | s16-div = primitive "s16-div" : S16 -> S16 -> S16; 128 | s32-div = primitive "s32-div" : S32 -> S32 -> S32; 129 | s64-div = primitive "s64-div" : S64 -> S64 -> S64; 130 | f32-div = primitive "f32-div" : F32 -> F32 -> F32; 131 | f64-div = primitive "f64-div" : F64 -> F64 -> F64; 132 | 133 | char-to-string = primitive "char-to-string" : Char -> String; 134 | u8-to-string = primitive "u8-to-string" : U8 -> String; 135 | u16-to-string = primitive "u16-to-string" : U16 -> String; 136 | u32-to-string = primitive "u32-to-string" : U32 -> String; 137 | u64-to-string = primitive "u64-to-string" : U64 -> String; 138 | s8-to-string = primitive "s8-to-string" : S8 -> String; 139 | s16-to-string = primitive "s16-to-string" : S16 -> String; 140 | s32-to-string = primitive "s32-to-string" : S32 -> String; 141 | s64-to-string = primitive "s64-to-string" : S64 -> String; 142 | f32-to-string = primitive "f32-to-string" : F32 -> String; 143 | f64-to-string = primitive "f64-to-string" : F64 -> String; 144 | 145 | u8-min = primitive "u8-min" : U8; 146 | u16-min = primitive "u16-min" : U16; 147 | u32-min = primitive "u32-min" : U32; 148 | u64-min = primitive "u64-min" : U64; 149 | s8-min = primitive "s8-min" : S8; 150 | s16-min = primitive "s16-min" : S16; 151 | s32-min = primitive "s32-min" : S32; 152 | s64-min = primitive "s64-min" : S64; 153 | 154 | u8-max = primitive "u8-max" : U8; 155 | u16-max = primitive "u16-max" : U16; 156 | u32-max = primitive "u32-max" : U32; 157 | u64-max = primitive "u64-max" : U64; 158 | s8-max = primitive "s8-max" : S8; 159 | s16-max = primitive "s16-max" : S16; 160 | s32-max = primitive "s32-max" : S32; 161 | s64-max = primitive "s64-max" : S64; 162 | 163 | f32-nan = primitive "f32-nan" : F32; 164 | f64-nan = primitive "f64-nan" : F64; 165 | 166 | f32-infinity = primitive "f32-infinity" : F32; 167 | f64-infinity = primitive "f64-infinity" : F64; 168 | 169 | f32-neg-infinity = primitive "f32-neg-infinity" : F32; 170 | f64-neg-infinity = primitive "f64-neg-infinity" : F64; 171 | -------------------------------------------------------------------------------- /tests/samples/records.mltt: -------------------------------------------------------------------------------- 1 | ||| Module for defining equality between two terms 2 | Eq : Type -> Type; 3 | Eq A = Record { 4 | ||| Compare two terms for equality 5 | eq : A -> A -> Bool; 6 | }; 7 | 8 | ||| Compare two terms for equality 9 | eq : Fun {A : Type} {{eq-A : Eq A}} -> A -> A -> Bool; 10 | eq {{eq-A}} a1 a2 = eq-A.eq a1 a2; 11 | 12 | bool-eq : Eq Bool; 13 | bool-eq = record { 14 | eq lhs rhs = 15 | if lhs then 16 | rhs 17 | else 18 | if rhs then false else true; 19 | }; 20 | 21 | 22 | Map = Record { 23 | Key : Type; 24 | Map : Type -> Type; 25 | 26 | empty : Fun {A : Type} -> Map A; 27 | add : Fun {A : Type} -> A -> Map A -> Map A; 28 | lookup : Fun {A : Type} -> Key -> A -> Map A -> A; -- TODO: return `Option A` 29 | }; 30 | --------------------------------------------------------------------------------