Skip to content

Commit c732d22

Browse files
committed
add parser torture testing framework
1 parent ba6ebaf commit c732d22

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use formality_core::term;
2+
use std::sync::Arc;
3+
4+
#[test]
5+
#[should_panic(expected = "ambiguous parse")] // FIXME: we want this example to work
6+
fn reduce_reduce_ok() {
7+
#[term]
8+
pub enum Root {
9+
#[cast]
10+
ClassTy(ClassTy),
11+
#[cast]
12+
Perm(Perm),
13+
}
14+
15+
#[term($perm $class_id)]
16+
pub struct ClassTy {
17+
perm: Perm,
18+
class_id: Id,
19+
}
20+
21+
#[term]
22+
pub enum Perm {
23+
My,
24+
Our,
25+
}
26+
27+
formality_core::id!(Id);
28+
29+
let term: Root = crate::ptt::term("my String");
30+
expect_test::expect![].assert_debug_eq(&term);
31+
}
32+
33+
#[test]
34+
#[should_panic(expected = "ambiguous parse")]
35+
fn reduce_reduce_ambig() {
36+
#[term]
37+
pub enum Root {
38+
#[grammar($v0)]
39+
OneId(Id),
40+
#[grammar($v0 $v1)]
41+
TwoId(Id, Id),
42+
#[grammar($v0 $v1)]
43+
TwoRr(Arc<Root>, Arc<Root>),
44+
}
45+
46+
formality_core::id!(Id);
47+
48+
// This will panic. It could be parsed in multiple ways
49+
// (using a variant of Reverse Polish Notation) and none is obviously
50+
// better than the other:
51+
//
52+
// Root = ((Id Root::OneId) (Id Id Root::TwoId) Root::TwoRr)
53+
// Root = (Id Id Root::TwoId) (Id Root::OneId) Root::TwoRr)
54+
// Root = ((Id Root::OneId) (Id Root::OneId) (Id Root::OneId) Root::TwoRr)
55+
let term: Root = crate::ptt::term("a b c");
56+
expect_test::expect![].assert_debug_eq(&term);
57+
}

tests/parser-torture-tests/grammar.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use crate::ptt::{
2+
grammar::{BoundVar, ExistentialVar, UniversalVar, Variable},
3+
FormalityLang,
4+
};
5+
use formality_core::{language::HasKind, term};
6+
7+
// Create a dummy kind/parameter -- we're not using these for the torture
8+
// tests, but we need them.
9+
10+
#[term]
11+
#[derive(Copy)]
12+
pub enum DummyKind {
13+
Ty,
14+
}
15+
16+
#[term]
17+
pub enum DummyParameter {
18+
#[cast]
19+
Ty(DummyTy),
20+
}
21+
22+
#[term]
23+
pub enum DummyTy {
24+
#[variable]
25+
Variable(Variable),
26+
}
27+
28+
formality_core::cast_impl!((BoundVar) <: (Variable) <: (DummyTy));
29+
formality_core::cast_impl!((ExistentialVar) <: (Variable) <: (DummyTy));
30+
formality_core::cast_impl!((UniversalVar) <: (Variable) <: (DummyTy));
31+
formality_core::cast_impl!((Variable) <: (DummyTy) <: (DummyParameter));
32+
formality_core::cast_impl!((BoundVar) <: (DummyTy) <: (DummyParameter));
33+
formality_core::cast_impl!((ExistentialVar) <: (DummyTy) <: (DummyParameter));
34+
formality_core::cast_impl!((UniversalVar) <: (DummyTy) <: (DummyParameter));
35+
36+
impl HasKind<FormalityLang> for DummyParameter {
37+
fn kind(&self) -> formality_core::language::CoreKind<FormalityLang> {
38+
match self {
39+
DummyParameter::Ty(_) => DummyKind::Ty,
40+
}
41+
}
42+
}

tests/parser-torture-tests/main.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
mod ambiguity;
2+
mod grammar;
3+
mod precedence;
4+
5+
formality_core::declare_language! {
6+
mod ptt {
7+
const NAME = "PTT";
8+
type Kind = crate::grammar::DummyKind;
9+
type Parameter = crate::grammar::DummyParameter;
10+
const BINDING_OPEN = '<';
11+
const BINDING_CLOSE = '>';
12+
const KEYWORDS = [
13+
"struct",
14+
"fn",
15+
"let",
16+
"in",
17+
"integer",
18+
];
19+
}
20+
}
21+
22+
// Default language for our crate
23+
use formality_core::Fallible;
24+
use ptt::FormalityLang;
25+
26+
fn main() -> Fallible<()> {
27+
Ok(())
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use formality_core::term;
2+
use std::sync::Arc;
3+
4+
#[test]
5+
fn precedence() {
6+
#[term]
7+
pub enum Root {
8+
#[cast]
9+
Id(Id),
10+
11+
#[grammar($v0 + $v1)]
12+
Add(Arc<Root>, Arc<Root>),
13+
14+
#[grammar($v0 * $v1)]
15+
#[precedence(1)]
16+
Mul(Arc<Root>, Arc<Root>),
17+
}
18+
19+
formality_core::id!(Id);
20+
21+
let term: Root = crate::ptt::term("a + b * c");
22+
expect_test::expect![[r#"
23+
a + b * c
24+
"#]]
25+
.assert_debug_eq(&term);
26+
}

0 commit comments

Comments
 (0)