Massive feature drop
- pattern matching seems to be correct - dynamic dispatch works with the to_string example - template strings as a last-minute addition - interpreter revamp, virtual stack for abort safety
This commit is contained in:
@@ -10,9 +10,7 @@ use intern_all::{sweep_t, Tok};
|
||||
use super::dealias::resolve_aliases::resolve_aliases;
|
||||
use super::process_source::{process_ns, resolve_globs, GlobImports};
|
||||
use super::project::{ItemKind, ProjItem, ProjXEnt, ProjectMod, ProjectTree};
|
||||
use crate::error::{
|
||||
bundle_location, ErrorPosition, ProjectError, ProjectResult,
|
||||
};
|
||||
use crate::error::{bundle_location, ErrorPosition, ProjectError, ProjectResult};
|
||||
use crate::location::{CodeGenInfo, CodeLocation, SourceCode, SourceRange};
|
||||
use crate::name::{PathSlice, Sym, VName, VPath};
|
||||
use crate::parse::context::ParseCtxImpl;
|
||||
@@ -42,10 +40,7 @@ fn split_max_prefix<'a, T>(
|
||||
path: &'a [T],
|
||||
is_valid: &impl Fn(&[T]) -> bool,
|
||||
) -> Option<(&'a [T], &'a [T])> {
|
||||
(0..=path.len())
|
||||
.rev()
|
||||
.map(|i| path.split_at(i))
|
||||
.find(|(file, _)| is_valid(file))
|
||||
(0..=path.len()).rev().map(|i| path.split_at(i)).find(|(file, _)| is_valid(file))
|
||||
}
|
||||
|
||||
/// Represents a prelude / implicit import requested by a library.
|
||||
@@ -94,10 +89,8 @@ pub fn load_solution(
|
||||
) -> ProjectResult<ProjectTree> {
|
||||
let mut target_queue = VecDeque::<(Sym, CodeLocation)>::new();
|
||||
target_queue.extend(targets.into_iter());
|
||||
target_queue.extend(
|
||||
(ctx.preludes.iter())
|
||||
.map(|p| (p.target.to_sym(), CodeLocation::Gen(p.owner.clone()))),
|
||||
);
|
||||
target_queue
|
||||
.extend((ctx.preludes.iter()).map(|p| (p.target.to_sym(), CodeLocation::Gen(p.owner.clone()))));
|
||||
let mut known_files = HashSet::new();
|
||||
let mut tree_acc: ProjectMod = Module::wrap([]);
|
||||
let mut glob_acc: GlobImports = Module::wrap([]);
|
||||
@@ -111,21 +104,16 @@ pub fn load_solution(
|
||||
}
|
||||
known_files.insert(filename.to_vec());
|
||||
let path = VPath(filename.to_vec());
|
||||
let loaded = fs
|
||||
.read(PathSlice(filename))
|
||||
.map_err(|e| bundle_location(&referrer, &*e))?;
|
||||
let loaded = fs.read(PathSlice(filename)).map_err(|e| bundle_location(&referrer, &*e))?;
|
||||
let code = match loaded {
|
||||
Loaded::Collection(_) =>
|
||||
return Err(UnexpectedDirectory { path }.pack()),
|
||||
Loaded::Collection(_) => return Err(UnexpectedDirectory { path }.pack()),
|
||||
Loaded::Code(source) => SourceCode { source, path: Arc::new(path) },
|
||||
};
|
||||
let full_range =
|
||||
SourceRange { range: 0..code.source.len(), code: code.clone() };
|
||||
let full_range = SourceRange { range: 0..code.source.len(), code: code.clone() };
|
||||
let lines = parse_file(&ctx.parsing(code.clone()))?;
|
||||
let report = process_ns(code.path, lines, full_range)?;
|
||||
target_queue.extend(
|
||||
(report.external_references.into_iter())
|
||||
.map(|(k, v)| (k, CodeLocation::Source(v))),
|
||||
(report.external_references.into_iter()).map(|(k, v)| (k, CodeLocation::Source(v))),
|
||||
);
|
||||
if !report.comments.is_empty() && filename.is_empty() {
|
||||
todo!("panic - module op comments on root are lost")
|
||||
@@ -137,23 +125,22 @@ pub fn load_solution(
|
||||
// i over valid indices of filename
|
||||
let key = filename[i].clone(); // last segment
|
||||
let comments = comments.take().into_iter().flatten().collect();
|
||||
glob =
|
||||
Module::wrap([(key.clone(), ModEntry::wrap(ModMember::Sub(glob)))]);
|
||||
glob = Module::wrap([(key.clone(), ModEntry::wrap(ModMember::Sub(glob)))]);
|
||||
module = Module::wrap([(key, ModEntry {
|
||||
member: ModMember::Sub(module),
|
||||
x: ProjXEnt { comments, ..Default::default() },
|
||||
})]);
|
||||
}
|
||||
glob_acc = (glob_acc.combine(glob))
|
||||
.expect("source code loaded for two nested paths");
|
||||
tree_acc = (tree_acc.combine(module))
|
||||
.expect("source code loaded for two nested paths");
|
||||
glob_acc = (glob_acc.combine(glob)).expect("source code loaded for two nested paths");
|
||||
tree_acc = (tree_acc.combine(module)).expect("source code loaded for two nested paths");
|
||||
} else {
|
||||
known_files.insert(target[..].to_vec());
|
||||
// If the path is not within a file, load it as directory
|
||||
match fs.read(target.as_path_slice()) {
|
||||
Ok(Loaded::Collection(c)) => target_queue
|
||||
.extend(c.iter().map(|e| (Sym::parse(e).unwrap(), referrer.clone()))),
|
||||
Ok(Loaded::Collection(c)) => target_queue.extend(c.iter().map(|e| {
|
||||
let name = VPath::new(target.iter()).as_prefix_of(e.clone()).to_sym();
|
||||
(name, referrer.clone())
|
||||
})),
|
||||
Ok(Loaded::Code(_)) => unreachable!("Should have split to self and []"),
|
||||
// Ignore error if the path is walkable in the const tree
|
||||
Err(_) if env.walk1_ref(&[], &target[..], |_| true).is_ok() => (),
|
||||
@@ -172,12 +159,10 @@ pub fn load_solution(
|
||||
)?;
|
||||
let ret = resolve_aliases(tree_acc, env)?;
|
||||
for ((glob, original), locations) in contention {
|
||||
let (glob_val, _) = ret
|
||||
.walk1_ref(&[], &glob[..], |_| true)
|
||||
.expect("Should've emerged in dealias");
|
||||
let (original_val, _) = ret
|
||||
.walk1_ref(&[], &original[..], |_| true)
|
||||
.expect("Should've emerged in dealias");
|
||||
let (glob_val, _) =
|
||||
ret.walk1_ref(&[], &glob[..], |_| true).expect("Should've emerged in dealias");
|
||||
let (original_val, _) =
|
||||
ret.walk1_ref(&[], &original[..], |_| true).expect("Should've emerged in dealias");
|
||||
let glob_real = match &glob_val.member {
|
||||
ModMember::Item(ProjItem { kind: ItemKind::Alias(glob_tgt) }) => glob_tgt,
|
||||
_ => &glob,
|
||||
@@ -208,9 +193,7 @@ struct UnexpectedDirectory {
|
||||
impl ProjectError for UnexpectedDirectory {
|
||||
const DESCRIPTION: &'static str = "A stage that deals specifically with code \
|
||||
encountered a path that refers to a directory";
|
||||
fn message(&self) -> String {
|
||||
format!("{} was expected to be a file", self.path)
|
||||
}
|
||||
fn message(&self) -> String { format!("{} was expected to be a file", self.path) }
|
||||
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> { [] }
|
||||
}
|
||||
|
||||
@@ -223,8 +206,7 @@ struct ConflictingGlobs {
|
||||
locations: Vec<CodeLocation>,
|
||||
}
|
||||
impl ProjectError for ConflictingGlobs {
|
||||
const DESCRIPTION: &'static str =
|
||||
"A symbol from a glob import conflicts with an existing name";
|
||||
const DESCRIPTION: &'static str = "A symbol from a glob import conflicts with an existing name";
|
||||
fn message(&self) -> String {
|
||||
let Self { glob, glob_real, original, real, .. } = self;
|
||||
format!(
|
||||
@@ -233,7 +215,6 @@ impl ProjectError for ConflictingGlobs {
|
||||
)
|
||||
}
|
||||
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> {
|
||||
(self.locations.iter())
|
||||
.map(|l| ErrorPosition { location: l.clone(), message: None })
|
||||
(self.locations.iter()).map(|l| ErrorPosition { location: l.clone(), message: None })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,9 @@ use never::Never;
|
||||
use super::load_solution::Prelude;
|
||||
use super::path::absolute_path;
|
||||
use super::project::{
|
||||
ItemKind, ProjItem, ProjRule, ProjXEnt, ProjXMod, ProjectEntry, ProjectMod,
|
||||
SourceModule,
|
||||
};
|
||||
use crate::error::{
|
||||
ErrorPosition, ProjectError, ProjectErrorObj, ProjectResult,
|
||||
ItemKind, ProjItem, ProjRule, ProjXEnt, ProjXMod, ProjectEntry, ProjectMod, SourceModule,
|
||||
};
|
||||
use crate::error::{ErrorPosition, ProjectError, ProjectErrorObj, ProjectResult};
|
||||
use crate::location::{CodeLocation, SourceRange};
|
||||
use crate::name::{Sym, VName, VPath};
|
||||
use crate::parse::parsed::{
|
||||
@@ -112,8 +109,7 @@ pub(super) fn process_ns(
|
||||
external_references.insert(abs.to_sym(), import.range.clone());
|
||||
}
|
||||
match import.name {
|
||||
None => (glob_imports.x.0)
|
||||
.push(GlobImpReport { target: abs, location: import.range }),
|
||||
None => (glob_imports.x.0).push(GlobImpReport { target: abs, location: import.range }),
|
||||
Some(key) => {
|
||||
let entry = get_or_make(&mut entries, &key, default_entry);
|
||||
entry.x.locations.push(CodeLocation::Source(import.range));
|
||||
@@ -151,8 +147,7 @@ pub(super) fn process_ns(
|
||||
entry.x.comments.append(&mut new_comments);
|
||||
},
|
||||
MemberKind::Rule(Rule { pattern, prio, template }) => {
|
||||
let prule =
|
||||
ProjRule { pattern, prio, template, comments: new_comments };
|
||||
let prule = ProjRule { pattern, prio, template, comments: new_comments };
|
||||
new_comments = Vec::new();
|
||||
for name in prule.collect_root_names() {
|
||||
let entry = get_or_make(&mut entries, &name, default_entry);
|
||||
@@ -171,10 +166,7 @@ pub(super) fn process_ns(
|
||||
MemberKind::Module(ModuleBlock { name, body }) => {
|
||||
let entry = get_or_make(&mut entries, &name, default_entry);
|
||||
entry.x.locations.push(CodeLocation::Source(range.clone()));
|
||||
if !matches!(
|
||||
entry.member,
|
||||
ModMember::Item(ProjItem { kind: ItemKind::None })
|
||||
) {
|
||||
if !matches!(entry.member, ModMember::Item(ProjItem { kind: ItemKind::None })) {
|
||||
let err = MultipleDefinitions {
|
||||
path: (*path).clone().as_prefix_of(name).to_sym(),
|
||||
locations: entry.x.locations.clone(),
|
||||
@@ -196,14 +188,12 @@ pub(super) fn process_ns(
|
||||
entry.member = ModMember::Sub(report.module);
|
||||
// record new external references
|
||||
external_references.extend(
|
||||
(report.external_references.into_iter())
|
||||
.filter(|(r, _)| !r[..].starts_with(&path.0)),
|
||||
(report.external_references.into_iter()).filter(|(r, _)| !r[..].starts_with(&path.0)),
|
||||
);
|
||||
// add glob_imports subtree to own tree
|
||||
glob_imports.entries.insert(name, ModEntry {
|
||||
x: (),
|
||||
member: ModMember::Sub(report.glob_imports),
|
||||
});
|
||||
glob_imports
|
||||
.entries
|
||||
.insert(name, ModEntry { x: (), member: ModMember::Sub(report.glob_imports) });
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -219,15 +209,10 @@ pub(super) fn process_ns(
|
||||
})
|
||||
}
|
||||
|
||||
fn walk_at_path(
|
||||
e: WalkError,
|
||||
root: &ProjectMod,
|
||||
path: &[Tok<String>],
|
||||
) -> ProjectErrorObj {
|
||||
let submod = (root.walk_ref(&[], path, |_| true))
|
||||
.expect("Invalid source path in walk error populator");
|
||||
let src =
|
||||
submod.x.src.as_ref().expect("Import cannot appear in implied module");
|
||||
fn walk_at_path(e: WalkError, root: &ProjectMod, path: &[Tok<String>]) -> ProjectErrorObj {
|
||||
let submod =
|
||||
(root.walk_ref(&[], path, |_| true)).expect("Invalid source path in walk error populator");
|
||||
let src = submod.x.src.as_ref().expect("Import cannot appear in implied module");
|
||||
e.at(&CodeLocation::Source(src.range.clone()))
|
||||
}
|
||||
|
||||
@@ -244,15 +229,12 @@ pub fn resolve_globs(
|
||||
contention: &mut HashMap<(Sym, Sym), Vec<CodeLocation>>,
|
||||
) -> ProjectResult<()> {
|
||||
// All glob imports in this module
|
||||
let all = (globtree.x.0.into_iter())
|
||||
.map(|gir| (gir.target, CodeLocation::Source(gir.location)))
|
||||
.chain(
|
||||
let all =
|
||||
(globtree.x.0.into_iter()).map(|gir| (gir.target, CodeLocation::Source(gir.location))).chain(
|
||||
preludes
|
||||
.iter()
|
||||
.filter(|&pre| !globtree_prefix.0.starts_with(&pre.exclude[..]))
|
||||
.map(|Prelude { target, owner, .. }| {
|
||||
(target.clone(), CodeLocation::Gen(owner.clone()))
|
||||
}),
|
||||
.map(|Prelude { target, owner, .. }| (target.clone(), CodeLocation::Gen(owner.clone()))),
|
||||
);
|
||||
for (target, location) in all {
|
||||
let (tgt, parent) = project_root
|
||||
@@ -272,13 +254,12 @@ pub fn resolve_globs(
|
||||
.chain(module.keys(|e| e.x.exported))
|
||||
.collect_vec();
|
||||
// Reference to the module to be modified
|
||||
let mut_mod =
|
||||
globtree_prefix.0.iter().fold(&mut *project_root, |m, k| {
|
||||
let entry = m.entries.get_mut(k).expect("this is a source path");
|
||||
unwrap_or!(&mut entry.member => ModMember::Sub; {
|
||||
panic!("This is also a source path")
|
||||
})
|
||||
});
|
||||
let mut_mod = globtree_prefix.0.iter().fold(&mut *project_root, |m, k| {
|
||||
let entry = m.entries.get_mut(k).expect("this is a source path");
|
||||
unwrap_or!(&mut entry.member => ModMember::Sub; {
|
||||
panic!("This is also a source path")
|
||||
})
|
||||
});
|
||||
// Walk errors for the environment are suppressed because leaf-node
|
||||
// conflicts will emerge when merging modules, and walking off the tree
|
||||
// is valid.
|
||||
@@ -286,23 +267,12 @@ pub fn resolve_globs(
|
||||
let entry = get_or_make(&mut mut_mod.entries, &key, default_entry);
|
||||
entry.x.locations.push(location.clone());
|
||||
let alias_tgt = target.clone().suffix([key.clone()]).to_sym();
|
||||
match &mut entry.member {
|
||||
ModMember::Item(ProjItem { kind: kref @ ItemKind::None }) =>
|
||||
*kref = ItemKind::Alias(alias_tgt),
|
||||
ModMember::Item(ProjItem { kind: ItemKind::Alias(prev_alias) }) =>
|
||||
if prev_alias != &alias_tgt {
|
||||
let local_name =
|
||||
globtree_prefix.clone().as_prefix_of(key.clone()).to_sym();
|
||||
let locs = pushed_ref(&entry.x.locations, location.clone());
|
||||
contention.insert((alias_tgt, local_name), locs);
|
||||
},
|
||||
_ => {
|
||||
let err = MultipleDefinitions {
|
||||
locations: entry.x.locations.clone(),
|
||||
path: globtree_prefix.as_prefix_of(key).to_sym(),
|
||||
};
|
||||
return Err(err.pack());
|
||||
},
|
||||
if let ModMember::Item(ProjItem { kind: kref @ ItemKind::None }) = &mut entry.member {
|
||||
*kref = ItemKind::Alias(alias_tgt)
|
||||
} else {
|
||||
let local_name = globtree_prefix.clone().as_prefix_of(key.clone()).to_sym();
|
||||
let locs = pushed_ref(&entry.x.locations, location.clone());
|
||||
contention.insert((alias_tgt, local_name), locs);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -313,14 +283,7 @@ pub fn resolve_globs(
|
||||
ModMember::Item(n) => match n {},
|
||||
ModMember::Sub(module) => {
|
||||
let subpath = VPath(pushed_ref(&globtree_prefix.0, key));
|
||||
resolve_globs(
|
||||
subpath,
|
||||
module,
|
||||
preludes.clone(),
|
||||
project_root,
|
||||
env,
|
||||
contention,
|
||||
)?;
|
||||
resolve_globs(subpath, module, preludes.clone(), project_root, env, contention)?;
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -333,12 +296,9 @@ struct MultipleExports {
|
||||
}
|
||||
impl ProjectError for MultipleExports {
|
||||
const DESCRIPTION: &'static str = "A symbol was exported in multiple places";
|
||||
fn message(&self) -> String {
|
||||
format!("{} exported multiple times", self.path)
|
||||
}
|
||||
fn message(&self) -> String { format!("{} exported multiple times", self.path) }
|
||||
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> {
|
||||
(self.locations.iter())
|
||||
.map(|l| ErrorPosition { location: l.clone(), message: None })
|
||||
(self.locations.iter()).map(|l| ErrorPosition { location: l.clone(), message: None })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,11 +308,8 @@ pub(super) struct MultipleDefinitions {
|
||||
}
|
||||
impl ProjectError for MultipleDefinitions {
|
||||
const DESCRIPTION: &'static str = "Symbol defined twice";
|
||||
fn message(&self) -> String {
|
||||
format!("{} refers to multiple conflicting items", self.path)
|
||||
}
|
||||
fn message(&self) -> String { format!("{} refers to multiple conflicting items", self.path) }
|
||||
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> {
|
||||
(self.locations.iter())
|
||||
.map(|l| ErrorPosition { location: l.clone(), message: None })
|
||||
(self.locations.iter()).map(|l| ErrorPosition { location: l.clone(), message: None })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ impl Display for ProjXMod {
|
||||
pub type ProjectEntry = ModEntry<ProjItem, ProjXMod, ProjXEnt>;
|
||||
/// A node in the tree describing the project
|
||||
pub type ProjectMod = Module<ProjItem, ProjXMod, ProjXEnt>;
|
||||
/// A reference to an item or module in the project
|
||||
pub type ProjectMemberRef<'a> = ModMemberRef<'a, ProjItem, ProjXMod, ProjXEnt>;
|
||||
|
||||
fn collect_rules_rec(bag: &mut Vec<ProjRule>, module: &ProjectMod) {
|
||||
@@ -267,5 +268,6 @@ pub struct ConstReport {
|
||||
pub comments: Vec<Arc<String>>,
|
||||
/// Value assigned to the constant
|
||||
pub value: Expr,
|
||||
/// Source location this constant was parsed from
|
||||
pub range: SourceRange,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user