Skip to content
Snippets Groups Projects
Commit a1aaf675 authored by aalbert's avatar aalbert
Browse files

Resolve "Pest parser"

Closes #3

Approved-by: default avatarbelazy <aarthuur01@gmail.com>
Approved-by: default avataraalbert <augustin.albert@bleu-azure.fr>

* fix(parser): Fix minor issues (impl PartialEq for tests)

* feat(parser): Add more inclusive syntax

* feat(parser): Add informative message for free variables

* fix(parser): Fix a conversion bug

* feat(parser,core): Move classic term from core into parser

* feat(parser): Conversion from classic terms to terms

* feat(core): Add conversion from classic term to term

* chore(parser): Rename pest file

* chore(core): Move classic terms in its own file

* feat(parser): Add ClassicTerm with variables for easier user input

* fix(parser): Reorganize lib.rs and parser.rs

* fix(parser): Reorganize lib.rs and parser.rs

* fix(parser): Reorganize lib.rs and parser.rs

* chore(parser): Rename tests files

* chore(parser): Rename tests files

* feat(parser): add parser for terms, commands and files

* feat(parser): add parser for terms, commands and files

* feat(parser): add parser for terms, commands and files

* feat(parser): add parser for terms, commands and files

* feat(parser): add parser for terms, commands and files

* feat(parser): add parser for terms, commands and files

* feat(parser): add parser for terms, commands and files

* chore(core): add license

* chore(parser): remove warnings

* chore(core): format files

* chore(parser): remove warnings

* chore(parser): format code

* fix(core): add lib.rs

* feat(term): Add early Term struct + Display trait

* feat(parser): add parser crate and pest config
parent 1c9c33a7
No related branches found
No related tags found
1 merge request!42Draft: Resolve "Preparations for the first release"
......@@ -3,5 +3,208 @@
version = 3
[[package]]
name = "proost"
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "core"
version = "0.1.0"
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "libc"
version = "0.2.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
[[package]]
name = "once_cell"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "parser"
version = "0.1.0"
dependencies = [
"core",
"pest",
"pest_derive",
]
[[package]]
name = "pest"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb779fcf4bb850fbbb0edc96ff6cf34fd90c4b1a112ce042653280d9a7364048"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "502b62a6d0245378b04ffe0a7fb4f4419a4815fce813bd8a0ec89a56e07d67b1"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "451e629bf49b750254da26132f1a5a9d11fd8a95a3df51d15c4abd1ba154cb6c"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcec162c71c45e269dfc3fc2916eaeb97feab22993a21bcce4721d08cd7801a6"
dependencies = [
"once_cell",
"pest",
"sha1",
]
[[package]]
name = "proc-macro2"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd7356a8122b6c4a24a82b278680c73357984ca2fc79a0f9fa6dea7dced7c58"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "syn"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a99cb8c4b9a8ef0e7907cd3b617cc8dc04d571c4e73c8ae403d80ac160bb122"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a891860d3c8d66fec8e73ddb3765f90082374dbaaa833407b904a94f1a7eb43"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unicode-ident"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
......@@ -2,4 +2,5 @@
members = [
"core",
"parser",
]
[package]
name = "proost"
name = "core"
version = "0.1.0"
edition = "2021"
package = "GPL-3.0-or-later"
license = "GPL-3.0-or-later"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
......
use crate::Term;
//use std::fmt::{Display, Formatter};
#[derive(Clone, Debug, PartialEq)]
pub enum Command {
Define(String, Term),
CheckType(Term, Term),
GetType(Term),
}
#![feature(box_syntax)]
mod command;
mod term;
pub use command::Command;
pub use term::Term;
use std::fmt::{Display, Formatter};
#[derive(Clone, Debug, PartialEq)]
pub enum Term {
Prop,
Var(usize),
Type(usize),
App(Box<Term>, Box<Term>),
Abs(Box<Term>, Box<Term>),
Prod(Box<Term>, Box<Term>),
}
impl Display for Term {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
Term::Prop => write!(f, "\u{02119}"),
Term::Var(i) => write!(f, "{}", i),
Term::Type(i) => write!(f, "\u{1D54B}({})", i),
Term::App(t1, t2) => write!(f, "({}) {}", t1, t2),
Term::Abs(t1, t2) => write!(f, "\u{003BB}{} \u{02192} {}", t1, t2),
Term::Prod(t1, t2) => write!(f, "\u{02200}{} \u{02192} {}", t1, t2),
}
}
}
[package]
name = "parser"
version = "0.1.0"
edition = "2021"
license = "GPL-3.0-or-later"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
core = { path = "../core" }
pest = "2.0"
pest_derive = "2.0"
WHITESPACE = _{ " " | "\t" }
COMMENT = _{ "#" ~ (!"\n" ~ ANY)* }
number = @{ ASCII_NONZERO_DIGIT ~ ASCII_DIGIT* }
string = @{ ASCII_ALPHA ~ ASCII_ALPHANUMERIC* }
Term = _{ Prop | Type | Var | App | Abs | Prod | ParTerm }
Prop = { "P" }
Type = { "T(" ~ number ~ ")" }
Var = { string }
App = { "(" ~ ( Var | Abs | Prod ) ~ ")" ~ Term }
Abs = { "/\\" ~ string ~ ":" ~ Term ~ "->" ~ Term }
Prod = { "\\/" ~ string ~ ":" ~ Term ~ "->" ~ Term }
ParTerm = _{ "(" ~ Term ~ ")" }
Command = _{ ( Define | CheckType | GetType ) ~ "." }
Define = { ( "define" | "Define" ) ~ string ~ ":=" ~ Term }
CheckType = { ( "CheckType" | "Check" | "check" ) ~ Term ~ ":" ~ Term }
GetType = { ( "Type" | "GetType" | "type" ) ~ Term }
File = { SOI ~ (NEWLINE* ~ Command)* ~ NEWLINE* ~ EOI }
use core::Term;
use std::fmt::{Display, Formatter};
#[derive(Clone, Debug)]
pub enum ClassicTerm {
Prop,
Var(String),
Type(usize),
App(Box<ClassicTerm>, Box<ClassicTerm>),
Abs(String, Box<ClassicTerm>, Box<ClassicTerm>),
Prod(String, Box<ClassicTerm>, Box<ClassicTerm>),
}
impl Display for ClassicTerm {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
ClassicTerm::Prop => write!(f, "\u{02119}"),
ClassicTerm::Var(i) => write!(f, "{}", i),
ClassicTerm::Type(i) => write!(f, "\u{1D54B}({})", i),
ClassicTerm::App(t1, t2) => write!(f, "({}) {}", t1, t2),
ClassicTerm::Abs(s, t1, t2) => write!(f, "\u{003BB}{} : {} \u{02192} {}", s, t1, t2),
ClassicTerm::Prod(s, t1, t2) => write!(f, "\u{02200}{} : {} \u{02192} {}", s, t1, t2),
}
}
}
fn try_from_assign(t: ClassicTerm, a: &mut Vec<String>) -> Result<Term, String> {
match t {
ClassicTerm::Prop => Ok(Term::Prop),
ClassicTerm::Type(i) => Ok(Term::Type(i)),
ClassicTerm::App(t1, t2) => {
let t1 = box try_from_assign(*t1, a)?;
let t2 = box try_from_assign(*t2, a)?;
Ok(Term::App(t1, t2))
}
ClassicTerm::Var(s) => match a.iter().rev().position(|r| *r == s) {
Some(i) => Ok(Term::Var(i + 1)),
None => Err(s),
},
ClassicTerm::Abs(s, t1, t2) => {
a.push(s);
let t1 = box try_from_assign(*t1, a)?;
let t2 = box try_from_assign(*t2, a)?;
a.pop();
Ok(Term::Abs(t1, t2))
}
ClassicTerm::Prod(s, t1, t2) => {
a.push(s);
let t1 = box try_from_assign(*t1, a)?;
let t2 = box try_from_assign(*t2, a)?;
a.pop();
Ok(Term::Prod(t1, t2))
}
}
}
impl TryFrom<ClassicTerm> for Term {
type Error = String;
fn try_from(t: ClassicTerm) -> Result<Self, Self::Error> {
try_from_assign(t, &mut Vec::new())
}
}
#![feature(box_syntax)]
#[macro_use]
extern crate pest_derive;
mod classic_term;
mod parser;
pub use self::parser::{parse_command, parse_file, parse_term};
use crate::classic_term::ClassicTerm;
use core::{Command, Term};
use pest::error::{Error, ErrorVariant};
use pest::iterators::Pair;
use pest::{Parser, Position};
#[derive(Parser)]
#[grammar = "classic_term.pest"]
struct CommandParser;
fn build_classic_term_from_expr(pair: Pair<Rule>) -> ClassicTerm {
match pair.as_rule() {
Rule::Prop => ClassicTerm::Prop,
Rule::Var => ClassicTerm::Var(pair.into_inner().as_str().to_string()),
Rule::Type => ClassicTerm::Type(pair.into_inner().as_str().parse().unwrap()),
Rule::App => {
let mut iter = pair.into_inner();
let t1 = build_classic_term_from_expr(iter.next().unwrap());
let t2 = build_classic_term_from_expr(iter.next().unwrap());
ClassicTerm::App(box t1, box t2)
}
Rule::Abs => {
let mut iter = pair.into_inner();
let s = iter.next().unwrap().as_str().to_string();
let t1 = build_classic_term_from_expr(iter.next().unwrap());
let t2 = build_classic_term_from_expr(iter.next().unwrap());
ClassicTerm::Abs(s, box t1, box t2)
}
Rule::Prod => {
let mut iter = pair.into_inner();
let s = iter.next().unwrap().as_str().to_string();
let t1 = build_classic_term_from_expr(iter.next().unwrap());
let t2 = build_classic_term_from_expr(iter.next().unwrap());
ClassicTerm::Prod(s, box t1, box t2)
}
term => panic!("Unexpected term: {:?}", term),
}
}
fn build_term_from_expr(pair: Pair<Rule>) -> Result<Term, String> {
Term::try_from(build_classic_term_from_expr(pair))
}
fn build_command_from_expr(pair: Pair<Rule>) -> Result<Command, String> {
match pair.as_rule() {
Rule::GetType => {
let mut iter = pair.into_inner();
let t = build_term_from_expr(iter.next().unwrap())?;
Ok(Command::GetType(t))
}
Rule::CheckType => {
let mut iter = pair.into_inner();
let t1 = build_term_from_expr(iter.next().unwrap())?;
let t2 = build_term_from_expr(iter.next().unwrap())?;
Ok(Command::CheckType(t1, t2))
}
Rule::Define => {
let mut iter = pair.into_inner();
let s = iter.next().unwrap().as_str().to_string();
let t = build_term_from_expr(iter.next().unwrap())?;
Ok(Command::Define(s, t))
}
command => panic!("Unexpected command: {:?}", command),
}
}
pub fn parse_term(file: &str) -> Result<Term, Box<Error<Rule>>> {
let pair = CommandParser::parse(Rule::Term, file)?.next().unwrap();
match build_term_from_expr(pair) {
Ok(t) => Ok(t),
Err(s) => Err(box Error::new_from_pos(
ErrorVariant::CustomError {
message: String::from("Free variable: ") + &s,
},
//TODO: Add more details, eg: variable position (#8)
Position::from_start(file),
)),
}
}
pub fn parse_command(file: &str) -> Result<Command, Box<Error<Rule>>> {
let pair = CommandParser::parse(Rule::Command, file)?.next().unwrap();
match build_command_from_expr(pair) {
Ok(t) => Ok(t),
Err(s) => Err(box Error::new_from_pos(
ErrorVariant::CustomError {
message: String::from("Free variable: ") + &s,
},
Position::from_start(file),
)),
}
}
// TODO: Unsatisfactory behavior (#7)
pub fn parse_file(file: &str) -> Result<Vec<Command>, Box<Error<Rule>>> {
let mut vec = Vec::new();
for pair in CommandParser::parse(Rule::File, file)?
.next()
.unwrap()
.into_inner()
{
match pair.as_rule() {
Rule::EOI => (),
_ => {
if let Ok(t) = build_command_from_expr(pair) {
vec.push(t)
}
}
}
}
Ok(vec)
}
Define Test := P.
use core::{Command, Term};
#[test]
fn parse() {
use std::fs;
let contents: &str =
&fs::read_to_string("tests/example.mdln").expect("Should have been able to read the file");
assert_eq!(
parser::parse_file(contents),
Ok(vec![Command::Define("Test".to_string(), Term::Prop)])
);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment