Difficult ownership questions
This commit is contained in:
@@ -1,57 +1,58 @@
|
||||
use chumsky::{Parser, prelude::*, text::Character};
|
||||
use std::iter;
|
||||
|
||||
use chumsky::{Parser, prelude::*};
|
||||
use super::name;
|
||||
|
||||
enum Import {
|
||||
Name(Vec<String>, String),
|
||||
All(Vec<String>)
|
||||
}
|
||||
|
||||
fn prefix(pre: Vec<String>, im: Import) -> Import {
|
||||
match im {
|
||||
Import::Name(ns, name) => Import::Name(
|
||||
pre.into_iter().chain(ns.into_iter()).collect(),
|
||||
name
|
||||
),
|
||||
Import::All(ns) => Import::All(
|
||||
pre.into_iter().chain(ns.into_iter()).collect()
|
||||
)
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Import {
|
||||
pub path: Vec<String>,
|
||||
pub name: Option<String>
|
||||
}
|
||||
|
||||
|
||||
type BoxedStrIter = Box<dyn Iterator<Item = String>>;
|
||||
type BoxedStrIterIter = Box<dyn Iterator<Item = BoxedStrIter>>;
|
||||
pub type BoxedStrIter = Box<dyn Iterator<Item = String>>;
|
||||
pub type BoxedStrIterIter = Box<dyn Iterator<Item = BoxedStrIter>>;
|
||||
|
||||
/// initialize a Box<dyn Iterator<Item = Box<dyn Iterator<Item = String>>>>
|
||||
/// with a single element.
|
||||
fn init_table(name: String) -> BoxedStrIterIter {
|
||||
Box::new(vec![Box::new(vec![name].into_iter()) as BoxedStrIter].into_iter())
|
||||
// I'm not confident at all that this is a good approach.
|
||||
Box::new(iter::once(Box::new(iter::once(name)) as BoxedStrIter))
|
||||
}
|
||||
|
||||
/// Parse an import command
|
||||
/// Syntax is same as Rust's `use` except the verb is import, no trailing semi
|
||||
/// and the delimiters are plain parentheses. Namespaces should preferably contain
|
||||
/// crossplatform filename-legal characters but the symbols are explicitly allowed
|
||||
/// to go wild. There's a blacklist in [name]
|
||||
pub fn import_parser() -> impl Parser<char, Vec<Import>, Error = Simple<char>> {
|
||||
// TODO: this algorithm isn't cache friendly, copies a lot and is generally pretty bad.
|
||||
recursive(|expr: Recursive<char, BoxedStrIterIter, Simple<char>>| {
|
||||
name::modname_parser()
|
||||
.padded()
|
||||
.then_ignore(just("::"))
|
||||
.repeated()
|
||||
.then(
|
||||
choice((
|
||||
expr.clone()
|
||||
.separated_by(just(','))
|
||||
.delimited_by(just('('), just(')'))
|
||||
.map(|v| Box::new(v.into_iter().flatten()) as BoxedStrIterIter),
|
||||
just("*").map(|s| init_table(s.to_string())),
|
||||
name::modname_parser().map(init_table)
|
||||
)).padded()
|
||||
).map(|(pre, post)| {
|
||||
Box::new(post.map(move |el| {
|
||||
Box::new(pre.clone().into_iter().chain(el)) as BoxedStrIter
|
||||
})) as BoxedStrIterIter
|
||||
})
|
||||
.padded()
|
||||
.then_ignore(just("::"))
|
||||
.repeated()
|
||||
.then(
|
||||
choice((
|
||||
expr.clone()
|
||||
.separated_by(just(','))
|
||||
.delimited_by(just('('), just(')'))
|
||||
.map(|v| Box::new(v.into_iter().flatten()) as BoxedStrIterIter),
|
||||
// Each expr returns a list of imports, flatten those into a common list
|
||||
just("*").map(|s| init_table(s.to_string())), // Just a *, wrapped
|
||||
name::modname_parser().map(init_table) // Just a name, wrapped
|
||||
)).padded()
|
||||
).map(|(pre, post)| {
|
||||
Box::new(post.map(move |el| {
|
||||
Box::new(pre.clone().into_iter().chain(el)) as BoxedStrIter
|
||||
})) as BoxedStrIterIter
|
||||
})
|
||||
}).padded().map(|paths| {
|
||||
paths.filter_map(|namespaces| {
|
||||
let mut path: Vec<String> = namespaces.collect();
|
||||
match path.pop()?.as_str() {
|
||||
"*" => Some(Import::All(path)),
|
||||
name => Some(Import::Name(path, name.to_owned()))
|
||||
"*" => Some(Import { path, name: None }),
|
||||
name => Some(Import { path, name: Some(name.to_owned()) })
|
||||
}
|
||||
}).collect()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user