1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Type checking for the lambda-Pi calculus modulo rewriting.
//!
//! This is the library underlying the [Kontroli] proof checker.
//!
//! # Usage
//!
//! Users communicate with Kontroli using *commands*.
//! A command either
//! introduces of a new name (by declaration, definition, or theorem), or
//! adds a rewrite rule.
//! The state of a Kontroli typechecking session consists of
//! a [`Symbols`] table, keeping track of all previously introduced names, and
//! a global context [`GCtx`], recording types and rewrite rules attached to symbols.
//!
//! How is a user command processed?
//! A command is parsed from a string to yield a [`parse::Command`].
//! Once we have a command, we distinguish whether it
//! introduces a name or adds a rewrite rule:
//! In case of a rewrite rule, we add the rewrite rule to the global context.
//! In case of a name introduction, we first
//! update the [`Symbols`] table with the newly introduced name and
//! verify that the given types and terms are valid, yielding a [`Typing`].
//! In both cases, [`share`](share::Share::share) refines terms in a command to shared terms,
//! verifying whether the names referenced in the terms,
//! have been previously declared in the [`Symbols`] table.
//! Once we have a typing, we add it to the global context.
//!
//! The following example parses a few commands and executes them on a global context.
//! (By the way, this example, just as all other code examples in this library,
//! can be executed by running `cargo test`.)
//!
//! ~~~
//! # use kontroli::{Command, Error, Share, Symbols};
//! # use kontroli::kernel::{self, GCtx};
//! # use colosseum::unsync::Arena;
//! let cmds = r#"
//! (; declarations ;)
//! prop : Type.
//! imp : prop -> prop -> prop.
//!
//! (; definition with a rewrite rule ;)
//! def proof : prop -> Type.
//! [x: prop, y: prop] proof (imp x y) --> proof x -> proof y.
//!
//! (; theorem ;)
//! thm imp_refl (x : prop) : proof (imp x x) := p : proof x => p.
//! "#;
//!
//! let arena = Arena::new();
//! let mut syms = Symbols::new();
//! let mut gc = GCtx::new();
//!
//! for cmd in kontroli::parse::Strict::new(cmds) {
//! // match constants in the command to previously introduced constants
//! let cmd = cmd.unwrap().share(&syms)?;
//! match cmd {
//! // introduction of a new name
//! Command::Intro(id, it) => {
//! let owned = kontroli::symbol::Owned::new(id.clone());
//! // add symbol to symbol table and fail if it is not new
//! let sym = syms.insert(id, arena.alloc(owned))?;
//!
//! // typecheck and insert into global context
//! let rewritable = it.rewritable();
//! let (typing, check) = kernel::intro(it, &gc)?;
//! if let Some(check) = check {
//! check.check(&gc)?
//! }
//! gc.insert(sym, typing, rewritable)?
//! }
//! // addition of rewrite rules (without typechecking them!)
//! Command::Rules(rules) => rules.into_iter().try_for_each(|r| gc.add_rule(r))?,
//! }
//! }
//! # Ok::<_, Error>(())
//! ~~~
//!
//! # Organisation
//!
//! This library is divided into several modules:
//! * The [`parse`] module contains unshared, reference-free data structures,
//! * the [`share`] module contains data structures with references, and
//! * the [`kernel`] module contains data structures with references and shared pointers.
//!
//! For many data structures, we have counterparts in
//! the [`parse`], [`share`], and [`kernel`] modules.
//! We call types from the [`parse`] and [`share`] modules
//! "parsed structures" and "shared structures", respectively.
//! For example, we distinguish parsed terms, shared terms, and (kernel) terms
//! (the latter being defined in the [`kernel`] module).
//! Parsed structures are constructed by the parser and
//! refined into their corresponding shared structures by the sharer.
//! Parsed and shared structures also implement the `Send` and `Sync` traits,
//! meaning that they can be transferred and shared between threads.
//! This allows parsing and checking to be performed in parallel.
//!
//! [Kontroli]: https://github.com/01mf02/kontroli-rs
extern crate alloc;
extern crate lazy_st;
extern crate log;
pub use dedukti_parse as parse;
pub use App;
pub use Comb;
pub use Command;
pub use Error;
pub use GCtx;
pub use LTerm;
pub use Intro;
pub use Pattern;
pub use Rule;
pub use Share;
pub use Symbol;
pub use Symbols;
pub use Typing;