Import and export improved

- Import paths are now vname and not sym
- Imports and exports accept multiple space-delimited operators in []

as a result, we can now reliably import and export the operator *

- error reporting ergonomics
This commit is contained in:
2023-08-18 21:10:29 +01:00
parent 3fdabc29da
commit 9186bce956
33 changed files with 269 additions and 228 deletions

View File

@@ -1,18 +1,45 @@
use std::collections::VecDeque;
use std::iter;
use super::context::Context;
use super::errors::{Expected, ExpectedName};
use super::errors::Expected;
use super::stream::Stream;
use super::Lexeme;
use crate::error::{ProjectError, ProjectResult};
use crate::utils::iter::{box_chain, box_once, BoxedIterIter};
use crate::sourcefile::Import;
use crate::utils::iter::{box_chain, box_once};
use crate::utils::BoxedIter;
use crate::Tok;
struct Subresult {
glob: bool,
deque: VecDeque<Tok<String>>,
}
impl Subresult {
fn new_glob() -> Self {
Self { glob: true, deque: VecDeque::new() }
}
fn new_named(name: Tok<String>) -> Self {
Self { glob: false, deque: VecDeque::from([name]) }
}
fn push_front(mut self, name: Tok<String>) -> Self {
self.deque.push_front(name);
self
}
fn finalize(self) -> Import {
let Self { mut deque, glob } = self;
debug_assert!(glob || !deque.is_empty(), "The constructors forbid this");
let name = if glob { None } else { deque.pop_back() };
Import { name, path: deque.into() }
}
}
fn parse_multiname_branch(
cursor: Stream<'_>,
ctx: impl Context,
) -> ProjectResult<(BoxedIterIter<Tok<String>>, Stream<'_>)> {
) -> ProjectResult<(BoxedIter<Subresult>, Stream<'_>)> {
let comma = ctx.interner().i(",");
let (subnames, cursor) = parse_multiname_rec(cursor, ctx.clone())?;
let (delim, cursor) = cursor.trim().pop()?;
@@ -33,30 +60,46 @@ fn parse_multiname_branch(
}
}
pub fn parse_multiname_rec(
fn parse_multiname_rec(
curosr: Stream<'_>,
ctx: impl Context,
) -> ProjectResult<(BoxedIterIter<Tok<String>>, Stream<'_>)> {
) -> ProjectResult<(BoxedIter<Subresult>, Stream<'_>)> {
let star = ctx.interner().i("*");
let comma = ctx.interner().i(",");
let (head, cursor) = curosr.trim().pop()?;
let (head, mut cursor) = curosr.trim().pop()?;
match &head.lexeme {
Lexeme::LP('(') => parse_multiname_branch(cursor, ctx),
Lexeme::LP('[') => {
let (op_ent, cursor) = cursor.trim().pop()?;
let op = ExpectedName::expect(op_ent)?;
let (rp_ent, cursor) = cursor.trim().pop()?;
Expected::expect(Lexeme::RP('['), rp_ent)?;
Ok((box_once(box_once(op)), cursor))
let mut names = Vec::new();
loop {
let head;
(head, cursor) = cursor.trim().pop()?;
match head.lexeme {
Lexeme::Name(n) => names.push(n),
Lexeme::RP('[') => break,
_ => {
let err = Expected {
expected: vec![Lexeme::RP('[')],
or_name: true,
found: head.clone(),
};
return Err(err.rc());
},
}
}
Ok((Box::new(names.into_iter().map(Subresult::new_named)), cursor))
},
Lexeme::Name(n) if *n != comma => {
Lexeme::Name(n) if *n == star =>
Ok((box_once(Subresult::new_glob()), cursor)),
Lexeme::Name(n) if ![comma, star].contains(n) => {
let cursor = cursor.trim();
if cursor.get(0).ok().map(|e| &e.lexeme) == Some(&Lexeme::NS) {
let cursor = cursor.step()?;
let (out, cursor) = parse_multiname_rec(cursor, ctx)?;
let out = Box::new(out.map(|i| box_chain!(i, iter::once(*n))));
let out = Box::new(out.map(|sr| sr.push_front(*n)));
Ok((out, cursor))
} else {
Ok((box_once(box_once(*n)), cursor))
Ok((box_once(Subresult::new_named(*n)), cursor))
}
},
_ => Err(
@@ -73,16 +116,7 @@ pub fn parse_multiname_rec(
pub fn parse_multiname(
cursor: Stream<'_>,
ctx: impl Context,
) -> ProjectResult<(Vec<Vec<Tok<String>>>, Stream<'_>)> {
) -> ProjectResult<(Vec<Import>, Stream<'_>)> {
let (output, cont) = parse_multiname_rec(cursor, ctx)?;
let output = output
.map(|it| {
let mut deque = VecDeque::with_capacity(it.size_hint().0);
for item in it {
deque.push_front(item)
}
deque.into()
})
.collect();
Ok((output, cont))
Ok((output.map(|sr| sr.finalize()).collect(), cont))
}