redid the parser, patched up the project too.

This commit is contained in:
2022-07-03 18:01:40 +02:00
parent 6fb4b581b1
commit 2b55fae10d
30 changed files with 967 additions and 570 deletions

View File

@@ -1,7 +1,9 @@
use std::iter;
use chumsky::{Parser, prelude::*};
use super::name;
use crate::{enum_parser, utils::BoxedIter};
use super::lexer::Lexeme;
#[derive(Debug, Clone)]
pub struct Import {
@@ -9,15 +11,10 @@ pub struct Import {
pub name: Option<String>
}
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 {
// I'm not confident at all that this is a good approach.
Box::new(iter::once(Box::new(iter::once(name)) as BoxedStrIter))
/// initialize a BoxedIter<BoxedIter<String>> with a single element.
fn init_table(name: String) -> BoxedIter<'static, BoxedIter<'static, String>> {
// I'm not at all confident that this is a good approach.
Box::new(iter::once(Box::new(iter::once(name)) as BoxedIter<String>))
}
/// Parse an import command
@@ -25,29 +22,38 @@ fn init_table(name: String) -> BoxedStrIterIter {
/// 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>> {
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<char, BoxedStrIterIter, Simple<char>>| {
name::modname_parser()
.padded()
.then_ignore(just("::"))
.repeated()
recursive(|expr: Recursive<Lexeme, BoxedIter<BoxedIter<String>>, Simple<Lexeme>>| {
enum_parser!(Lexeme::Name)
.separated_by(just(Lexeme::NS))
.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
just(Lexeme::NS)
.ignore_then(
choice((
expr.clone()
.separated_by(just(Lexeme::name(",")))
.delimited_by(just(Lexeme::LP('(')), just(Lexeme::RP('(')))
.map(|v| Box::new(v.into_iter().flatten()) as BoxedIter<BoxedIter<String>>)
.labelled("import group"),
// Each expr returns a list of imports, flatten those into a common list
just(Lexeme::name("*")).map(|_| init_table("*".to_string()))
.labelled("wildcard import"), // Just a *, wrapped
enum_parser!(Lexeme::Name).map(init_table)
.labelled("import terminal") // Just a name, wrapped
))
).or_not()
)
.map(|(name, opt_post): (Vec<String>, Option<BoxedIter<BoxedIter<String>>>)| -> BoxedIter<BoxedIter<String>> {
if let Some(post) = opt_post {
Box::new(post.map(move |el| {
Box::new(name.clone().into_iter().chain(el)) as BoxedIter<String>
})) as BoxedIter<BoxedIter<String>>
} else {
Box::new(iter::once(Box::new(name.into_iter()) as BoxedIter<String>))
}
})
}).padded().map(|paths| {
}).map(|paths| {
paths.filter_map(|namespaces| {
let mut path: Vec<String> = namespaces.collect();
match path.pop()?.as_str() {
@@ -55,5 +61,5 @@ pub fn import_parser() -> impl Parser<char, Vec<Import>, Error = Simple<char>> {
name => Some(Import { path, name: Some(name.to_owned()) })
}
}).collect()
})
}).labelled("import")
}