4 releases (2 breaking)

0.3.1 Jun 9, 2022
0.3.0 Jun 9, 2022
0.2.0 Sep 2, 2021
0.1.0 Jul 13, 2021

#4 in #dependent-types


Used in 2 crates (via kontroli)

GPL-3.0-only

47KB
1K SLoC

Parser for the Dedukti file format

This crate serves to parse Dedukti theory files. The syntax of Dedukti theories is documented here.

One of the main targets of this crate is speed: An evaluation of an older version of this crate in the article Safe, Fast, Concurrent Proof Checking for the lambda-Pi Calculus Modulo Rewriting showed that this parser can be more than 4x faster than the parser in Dedukti. This is relevant because the runtime of parsing can make up for nearly half the total runtime of Dedukti.

This crate currently does not support the complete Dedukti syntax; in particular, commands starting with #, such as #EVAL and #REQUIRE are not supported. Still, the supported subset of the syntax suffices to parse many large proof corpora, such as those produced from Matita, HOL Light, and Isabelle/HOL.

Usage

Lazy / Strict

This crate supports several modes of operation:

  • [Strict] parsing: The whole content of the file is in memory before parsing.
  • [Lazy] parsing: The file is read bit by bit during parsing.

Strict parsing of a whole file is faster than lazy parsing; however, it consumes more memory than lazy parsing and takes longer to get the first command.

Scoping

One important operation that is performed during parsing is scoping. This operation decides how to store symbols occurring in a term. There are currently two options:

  1. All symbols are unconditionally stored using strings.
  2. Symbols are distinguished into atoms that are either constants and variables, where constants are saved using strings and variables as de Bruijn indices (natural numbers that refer to the position of the binder of the variable).

The first option can use String and &str as string type. However, &str can be only used in conjunction with strict parsing, because lazy parsing "forgets" the input string and therefore does not allow references into the input string. The second option can be used regardless of strict or lazy parsing.

When to use what?

  • Use lazy parsing if you want to wait as little as possible to get each command or minimise your memory consumption.
  • Use strict parsing if you parse a whole file and wish to reduce the total runtime of parsing.
  • Store symbols unconditionally using strings if you do not care whether a symbol is a variable or not. In that case, when doing strict parsing, prefer &str over String as string type to reduce String allocations.

Example

use dedukti_parse::{term, Command, Error, Lazy, Scoped, Strict, Symb};

let cmds = r#"
    prop: Type.
    def proof : prop -> Type.
"#;

// strict parsing with `&str` symbols
let parse = Strict::<_, Symb<&str>, &str>::new(&cmds);
let parse: Result<Vec<_>, _> = parse.collect();
assert_eq!(parse?.len(), 2);

// strict parsing with atoms
let parse = Strict::<_, term::Atom<Symb<String>>, String>::new(cmds);
let parse: Result<Vec<_>, _> = parse.collect();
assert_eq!(parse?.len(), 2);

// lazy parsing with `String` symbols
let parse = Lazy::<_, Symb<String>, String>::new(cmds.lines());
let parse: Result<Vec<_>, _> = parse.collect();
assert_eq!(parse?.len(), 2);

// lazy parsing with atoms
let parse = Lazy::<_, term::Atom<Symb<String>>, String>::new(cmds.lines());
let parse: Result<Vec<_>, _> = parse.collect();
assert_eq!(parse?.len(), 2);

Dependencies

~1.5MB