Transfer commit
This commit is contained in:
@@ -1,34 +1,33 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use chumsky::{Parser, prelude::*};
|
||||
use itertools::Itertools;
|
||||
use mappable_rc::Mrc;
|
||||
use lasso::Spur;
|
||||
use crate::representations::sourcefile::Import;
|
||||
use crate::utils::iter::{box_once, box_flatten, into_boxed_iter, BoxedIterIter};
|
||||
use crate::utils::{to_mrc_slice, mrc_derive};
|
||||
use crate::{enum_parser, box_chain};
|
||||
|
||||
use super::lexer::Lexeme;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Import {
|
||||
pub path: Mrc<[String]>,
|
||||
/// If name is None, this is a wildcard import
|
||||
pub name: Option<String>
|
||||
}
|
||||
|
||||
/// initialize a BoxedIter<BoxedIter<String>> with a single element.
|
||||
fn init_table(name: String) -> BoxedIterIter<'static, String> {
|
||||
fn init_table(name: Spur) -> BoxedIterIter<'static, Spur> {
|
||||
// I'm not at all confident that this is a good approach.
|
||||
box_once(box_once(name))
|
||||
}
|
||||
|
||||
/// 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<Lexeme, Vec<Import>, Error = Simple<Lexeme>> {
|
||||
// TODO: this algorithm isn't cache friendly, copies a lot and is generally pretty bad.
|
||||
recursive(|expr: Recursive<Lexeme, BoxedIterIter<String>, Simple<Lexeme>>| {
|
||||
enum_parser!(Lexeme::Name)
|
||||
/// 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<'a, F>(intern: &'a F)
|
||||
-> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme>> + 'a
|
||||
where F: Fn(&str) -> Spur + 'a {
|
||||
let globstar = intern("*");
|
||||
// TODO: this algorithm isn't cache friendly and copies a lot
|
||||
recursive(move |expr:Recursive<Lexeme, BoxedIterIter<Spur>, Simple<Lexeme>>| {
|
||||
enum_parser!(Lexeme::Name).map(|s| intern(s.as_str()))
|
||||
.separated_by(just(Lexeme::NS))
|
||||
.then(
|
||||
just(Lexeme::NS)
|
||||
@@ -39,15 +38,17 @@ pub fn import_parser() -> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme
|
||||
.delimited_by(just(Lexeme::LP('(')), just(Lexeme::RP('(')))
|
||||
.map(|v| box_flatten(v.into_iter()))
|
||||
.labelled("import group"),
|
||||
// Each expr returns a list of imports, flatten those into a common list
|
||||
just(Lexeme::name("*")).map(|_| init_table("*".to_string()))
|
||||
// Each expr returns a list of imports, flatten into common list
|
||||
just(Lexeme::name("*")).map(move |_| init_table(globstar))
|
||||
.labelled("wildcard import"), // Just a *, wrapped
|
||||
enum_parser!(Lexeme::Name).map(init_table)
|
||||
enum_parser!(Lexeme::Name)
|
||||
.map(|s| init_table(intern(s.as_str())))
|
||||
.labelled("import terminal") // Just a name, wrapped
|
||||
))
|
||||
).or_not()
|
||||
)
|
||||
.map(|(name, opt_post): (Vec<String>, Option<BoxedIterIter<String>>)| -> BoxedIterIter<String> {
|
||||
.map(|(name, opt_post): (Vec<Spur>, Option<BoxedIterIter<Spur>>)|
|
||||
-> BoxedIterIter<Spur> {
|
||||
if let Some(post) = opt_post {
|
||||
Box::new(post.map(move |el| {
|
||||
box_chain!(name.clone().into_iter(), el)
|
||||
@@ -56,14 +57,17 @@ pub fn import_parser() -> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme
|
||||
box_once(into_boxed_iter(name))
|
||||
}
|
||||
})
|
||||
}).map(|paths| {
|
||||
}).map(move |paths| {
|
||||
paths.filter_map(|namespaces| {
|
||||
let path = to_mrc_slice(namespaces.collect_vec());
|
||||
let path_prefix = mrc_derive(&path, |p| &p[..p.len() - 1]);
|
||||
match path.last()?.as_str() {
|
||||
"*" => Some(Import { path: path_prefix, name: None }),
|
||||
name => Some(Import { path: path_prefix, name: Some(name.to_owned()) })
|
||||
}
|
||||
let mut path = namespaces.collect_vec();
|
||||
let name = path.pop()?;
|
||||
Some(Import {
|
||||
path: Rc::new(path),
|
||||
name: {
|
||||
if name == globstar { None }
|
||||
else { Some(name.to_owned()) }
|
||||
}
|
||||
})
|
||||
}).collect()
|
||||
}).labelled("import")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user