Skip to content

Commit db321a8

Browse files
committed
Merge branch 'master' of github.com-functora:functora/functora.github.io
2 parents 134a6e9 + 3a3fa85 commit db321a8

File tree

3 files changed

+233
-30
lines changed

3 files changed

+233
-30
lines changed

rust/rustell/src/lib.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
pub use chumsky::prelude::Parser;
2+
use chumsky::prelude::*;
3+
4+
#[derive(Eq, PartialEq, Debug, Clone)]
5+
pub enum Expr<'src> {
6+
Use(UseExpr<'src>),
7+
Other(&'src str),
8+
}
9+
10+
#[derive(Eq, PartialEq, Debug, Clone)]
11+
pub enum UseExpr<'src> {
12+
Path {
13+
ident: &'src str,
14+
rename: Option<&'src str>,
15+
nested: Option<Box<UseExpr<'src>>>,
16+
},
17+
Group(Vec<UseExpr<'src>>),
18+
Glob,
19+
}
20+
21+
pub fn parser<'src>()
22+
-> impl Parser<'src, &'src str, Vec<Expr<'src>>, extra::Err<Rich<'src, char>>> {
23+
let use_expr = || {
24+
just("use")
25+
.padded()
26+
.ignore_then(use_parser())
27+
.then_ignore(just(";").padded().or_not())
28+
.map(Expr::Use)
29+
};
30+
31+
let other = use_expr()
32+
.not()
33+
.ignore_then(any())
34+
.repeated()
35+
.at_least(1)
36+
.to_slice()
37+
.map(Expr::Other);
38+
39+
use_expr().or(other).repeated().collect::<Vec<_>>()
40+
}
41+
42+
fn use_parser<'src>()
43+
-> impl Parser<'src, &'src str, UseExpr<'src>, extra::Err<Rich<'src, char>>> {
44+
recursive(|use_parser| {
45+
let ident = || text::ascii::ident().padded();
46+
let path = ident()
47+
.then(just("as").padded().ignore_then(ident()).or_not())
48+
.then(just("::").padded().ignore_then(use_parser.clone()).or_not())
49+
.map(|((ident, rename), nested)| UseExpr::Path {
50+
ident,
51+
rename,
52+
nested: nested.map(Box::new),
53+
});
54+
55+
let group = use_parser
56+
.separated_by(just(','))
57+
.collect::<Vec<_>>()
58+
.delimited_by(just('{'), just('}'))
59+
.map(UseExpr::Group);
60+
61+
let glob = just("*").padded().map(|_| UseExpr::Glob);
62+
63+
path.or(group).or(glob)
64+
})
65+
}

rust/rustell/src/main.rs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,6 @@
1-
use chumsky::prelude::*;
1+
use rustell::*;
22
use std::io::{self, Read};
33

4-
#[derive(Clone, Debug)]
5-
pub enum Stmt {
6-
Expr,
7-
Loop(Vec<Stmt>),
8-
}
9-
10-
fn parser<'a>() -> impl Parser<'a, &'a str, Vec<Stmt>> {
11-
let expr = just("expr"); // TODO
12-
13-
let block = recursive(|block| {
14-
let indent = just(' ')
15-
.repeated()
16-
.configure(|cfg, parent_indent| cfg.exactly(*parent_indent));
17-
18-
let expr_stmt = expr.then_ignore(text::newline()).to(Stmt::Expr);
19-
let control_flow = just("loop:")
20-
.then(text::newline())
21-
.ignore_then(block)
22-
.map(Stmt::Loop);
23-
let stmt = expr_stmt.or(control_flow);
24-
25-
text::whitespace()
26-
.count()
27-
.ignore_with_ctx(stmt.separated_by(indent).collect())
28-
});
29-
30-
block.with_ctx(0)
31-
}
32-
334
fn main() {
345
let mut src = String::new();
356
io::stdin()

rust/rustell/tests/integration.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
use rustell::*;
2+
3+
#[test]
4+
fn test_parser() {
5+
let src = "use std::io::Read;";
6+
let lhs = parser().parse(src).into_result().unwrap();
7+
let rhs = vec![Expr::Use(UseExpr::Path {
8+
ident: "std",
9+
rename: None,
10+
nested: Some(Box::new(UseExpr::Path {
11+
ident: "io",
12+
rename: None,
13+
nested: Some(Box::new(UseExpr::Path {
14+
ident: "Read",
15+
rename: None,
16+
nested: None,
17+
})),
18+
})),
19+
})];
20+
assert_eq!(lhs, rhs)
21+
}
22+
23+
#[test]
24+
fn test_parser_group() {
25+
let src = "use std::{io::Read, fs::File};";
26+
let lhs = parser().parse(src).into_result().unwrap();
27+
let rhs = vec![Expr::Use(UseExpr::Path {
28+
ident: "std",
29+
rename: None,
30+
nested: Some(Box::new(UseExpr::Group(vec![
31+
UseExpr::Path {
32+
ident: "io",
33+
rename: None,
34+
nested: Some(Box::new(UseExpr::Path {
35+
ident: "Read",
36+
rename: None,
37+
nested: None,
38+
})),
39+
},
40+
UseExpr::Path {
41+
ident: "fs",
42+
rename: None,
43+
nested: Some(Box::new(UseExpr::Path {
44+
ident: "File",
45+
rename: None,
46+
nested: None,
47+
})),
48+
},
49+
]))),
50+
})];
51+
assert_eq!(lhs, rhs);
52+
}
53+
54+
#[test]
55+
fn test_parser_glob() {
56+
let src = "use std::io::*;";
57+
let lhs = parser().parse(src).into_result().unwrap();
58+
let rhs = vec![Expr::Use(UseExpr::Path {
59+
ident: "std",
60+
rename: None,
61+
nested: Some(Box::new(UseExpr::Path {
62+
ident: "io",
63+
rename: None,
64+
nested: Some(Box::new(UseExpr::Glob)),
65+
})),
66+
})];
67+
assert_eq!(lhs, rhs)
68+
}
69+
70+
#[test]
71+
fn test_parser_rename() {
72+
let src = "use std::io::Read as Readable;";
73+
let lhs = parser().parse(src).into_result().unwrap();
74+
let rhs = vec![Expr::Use(UseExpr::Path {
75+
ident: "std",
76+
rename: None,
77+
nested: Some(Box::new(UseExpr::Path {
78+
ident: "io",
79+
rename: None,
80+
nested: Some(Box::new(UseExpr::Path {
81+
ident: "Read",
82+
rename: Some("Readable"),
83+
nested: None,
84+
})),
85+
})),
86+
})];
87+
assert_eq!(lhs, rhs)
88+
}
89+
90+
#[test]
91+
fn test_parser_complex() {
92+
let src = "use std::{io::Read as Readable, fs::*};";
93+
let lhs = parser().parse(src).into_result().unwrap();
94+
let rhs = vec![Expr::Use(UseExpr::Path {
95+
ident: "std",
96+
rename: None,
97+
nested: Some(Box::new(UseExpr::Group(vec![
98+
UseExpr::Path {
99+
ident: "io",
100+
rename: None,
101+
nested: Some(Box::new(UseExpr::Path {
102+
ident: "Read",
103+
rename: Some("Readable"),
104+
nested: None,
105+
})),
106+
},
107+
UseExpr::Path {
108+
ident: "fs",
109+
rename: None,
110+
nested: Some(Box::new(UseExpr::Glob)),
111+
},
112+
]))),
113+
})];
114+
assert_eq!(lhs, rhs)
115+
}
116+
117+
#[test]
118+
fn test_parser_crate() {
119+
let src = "use crate::module::Type;";
120+
let lhs = parser().parse(src).into_result().unwrap();
121+
let rhs = vec![Expr::Use(UseExpr::Path {
122+
ident: "crate",
123+
rename: None,
124+
nested: Some(Box::new(UseExpr::Path {
125+
ident: "module",
126+
rename: None,
127+
nested: Some(Box::new(UseExpr::Path {
128+
ident: "Type",
129+
rename: None,
130+
nested: None,
131+
})),
132+
})),
133+
})];
134+
assert_eq!(lhs, rhs)
135+
}
136+
137+
#[test]
138+
fn test_parser_other_then_use() {
139+
let src = r#"
140+
fn test() {
141+
println!("Hello");
142+
}
143+
use crate::module::Type;"#;
144+
let lhs = parser().parse(src).into_result().unwrap();
145+
let rhs = vec![
146+
Expr::Other(
147+
r#"
148+
fn test() {
149+
println!("Hello");
150+
}"#,
151+
),
152+
Expr::Use(UseExpr::Path {
153+
ident: "crate",
154+
rename: None,
155+
nested: Some(Box::new(UseExpr::Path {
156+
ident: "module",
157+
rename: None,
158+
nested: Some(Box::new(UseExpr::Path {
159+
ident: "Type",
160+
rename: None,
161+
nested: None,
162+
})),
163+
})),
164+
}),
165+
];
166+
assert_eq!(lhs, rhs)
167+
}

0 commit comments

Comments
 (0)