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:
@@ -1,9 +1,7 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{ErrorPosition, ProjectError};
|
use super::ProjectError;
|
||||||
use crate::representations::location::Location;
|
use crate::representations::location::Location;
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
|
||||||
use crate::{Interner, VName};
|
use crate::{Interner, VName};
|
||||||
|
|
||||||
/// Error produced for the statement `import *`
|
/// Error produced for the statement `import *`
|
||||||
@@ -22,13 +20,7 @@ impl ProjectError for ImportAll {
|
|||||||
format!("{} imports *", i.extern_all(&self.offender_mod).join("::"))
|
format!("{} imports *", i.extern_all(&self.offender_mod).join("::"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition {
|
Location::File(self.offender_file.clone())
|
||||||
location: Location::File(self.offender_file.clone()),
|
|
||||||
message: Some(format!(
|
|
||||||
"{} imports *",
|
|
||||||
i.extern_all(&self.offender_mod).join("::")
|
|
||||||
)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use super::{ErrorPosition, ProjectError};
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::ProjectError;
|
||||||
use crate::representations::project::ProjectModule;
|
use crate::representations::project::ProjectModule;
|
||||||
#[allow(unused)] // For doc
|
#[allow(unused)] // For doc
|
||||||
use crate::tree::Module;
|
use crate::tree::Module;
|
||||||
use crate::tree::WalkError;
|
use crate::tree::WalkError;
|
||||||
use crate::utils::iter::box_once;
|
use crate::{Interner, Location, NameLike, Tok, VName};
|
||||||
use crate::utils::BoxedIter;
|
|
||||||
use crate::{Interner, NameLike, Tok, VName};
|
|
||||||
|
|
||||||
/// Error produced when an import refers to a nonexistent module
|
/// Error produced when an import refers to a nonexistent module
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
@@ -64,7 +64,7 @@ impl ProjectError for NotFound {
|
|||||||
i.extern_all(&self.file).join("/"),
|
i.extern_all(&self.file).join("/"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, i: &Interner) -> crate::Location {
|
||||||
box_once(ErrorPosition::just_file(i.extern_all(&self.file)))
|
Location::File(Rc::new(i.extern_all(&self.file)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use crate::interner::InternedDisplay;
|
use crate::interner::InternedDisplay;
|
||||||
use crate::representations::location::Location;
|
use crate::representations::location::Location;
|
||||||
|
use crate::utils::iter::box_once;
|
||||||
use crate::utils::BoxedIter;
|
use crate::utils::BoxedIter;
|
||||||
use crate::Interner;
|
use crate::Interner;
|
||||||
|
|
||||||
@@ -14,13 +15,6 @@ pub struct ErrorPosition {
|
|||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorPosition {
|
|
||||||
/// An error position referring to an entire file with no comment
|
|
||||||
pub fn just_file(file: Vec<String>) -> Self {
|
|
||||||
Self { message: None, location: Location::File(Rc::new(file)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Errors addressed to the developer which are to be resolved with
|
/// Errors addressed to the developer which are to be resolved with
|
||||||
/// code changes
|
/// code changes
|
||||||
pub trait ProjectError {
|
pub trait ProjectError {
|
||||||
@@ -30,8 +24,16 @@ pub trait ProjectError {
|
|||||||
fn message(&self, _i: &Interner) -> String {
|
fn message(&self, _i: &Interner) -> String {
|
||||||
self.description().to_string()
|
self.description().to_string()
|
||||||
}
|
}
|
||||||
/// Code positions relevant to this error
|
/// Code positions relevant to this error. If you don't implement this, you
|
||||||
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition>;
|
/// must implement [ProjectError::one_position]
|
||||||
|
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
|
||||||
|
box_once(ErrorPosition { location: self.one_position(i), message: None })
|
||||||
|
}
|
||||||
|
/// Short way to provide a single location. If you don't implement this, you
|
||||||
|
/// must implement [ProjectError::positions]
|
||||||
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
/// Convert the error into an `Rc<dyn ProjectError>` to be able to
|
/// Convert the error into an `Rc<dyn ProjectError>` to be able to
|
||||||
/// handle various errors together
|
/// handle various errors together
|
||||||
fn rc(self) -> Rc<dyn ProjectError>
|
fn rc(self) -> Rc<dyn ProjectError>
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::{ErrorPosition, ProjectError};
|
use super::ProjectError;
|
||||||
use crate::representations::location::Location;
|
use crate::representations::location::Location;
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
|
||||||
use crate::{Interner, VName};
|
use crate::{Interner, VName};
|
||||||
|
|
||||||
/// Error produced when an import path starts with more `super` segments
|
/// Error produced when an import path starts with more `super` segments
|
||||||
@@ -30,14 +28,7 @@ impl ProjectError for TooManySupers {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition {
|
Location::File(Rc::new(i.extern_all(&self.offender_file)))
|
||||||
location: Location::File(Rc::new(i.extern_all(&self.offender_file))),
|
|
||||||
message: Some(format!(
|
|
||||||
"path {} in {} contains too many `super` steps.",
|
|
||||||
i.extern_all(&self.path).join("::"),
|
|
||||||
i.extern_all(&self.offender_mod).join("::")
|
|
||||||
)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::{ErrorPosition, ProjectError};
|
use std::rc::Rc;
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
use super::ProjectError;
|
||||||
use crate::{Interner, VName};
|
use crate::{Interner, Location, VName};
|
||||||
|
|
||||||
/// Produced when a stage that deals specifically with code encounters
|
/// Produced when a stage that deals specifically with code encounters
|
||||||
/// a path that refers to a directory
|
/// a path that refers to a directory
|
||||||
@@ -15,9 +15,10 @@ impl ProjectError for UnexpectedDirectory {
|
|||||||
"A stage that deals specifically with code encountered a path that refers \
|
"A stage that deals specifically with code encountered a path that refers \
|
||||||
to a directory"
|
to a directory"
|
||||||
}
|
}
|
||||||
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, i: &Interner) -> crate::Location {
|
||||||
box_once(ErrorPosition::just_file(i.extern_all(&self.path)))
|
Location::File(Rc::new(i.extern_all(&self.path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn message(&self, i: &Interner) -> String {
|
fn message(&self, i: &Interner) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} was expected to be a file but a directory was found",
|
"{} was expected to be a file but a directory was found",
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use super::project_error::{ErrorPosition, ProjectError};
|
use super::project_error::ProjectError;
|
||||||
use crate::representations::location::Location;
|
use crate::representations::location::Location;
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
|
||||||
use crate::{Interner, VName};
|
use crate::{Interner, VName};
|
||||||
|
|
||||||
/// Multiple occurences of the same namespace with different visibility
|
/// Multiple occurences of the same namespace with different visibility
|
||||||
@@ -18,13 +16,13 @@ impl ProjectError for VisibilityMismatch {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Some occurences of a namespace are exported but others are not"
|
"Some occurences of a namespace are exported but others are not"
|
||||||
}
|
}
|
||||||
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn message(&self, i: &Interner) -> String {
|
||||||
box_once(ErrorPosition {
|
format!(
|
||||||
location: Location::File(self.file.clone()),
|
|
||||||
message: Some(format!(
|
|
||||||
"{} is opened multiple times with different visibilities",
|
"{} is opened multiple times with different visibilities",
|
||||||
i.extern_all(&self.namespace).join("::")
|
i.extern_all(&self.namespace).join("::")
|
||||||
)),
|
)
|
||||||
})
|
}
|
||||||
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
|
Location::File(self.file.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ use std::rc::Rc;
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use super::{Process, System};
|
use super::{Process, System};
|
||||||
use crate::error::{ErrorPosition, ProjectError, ProjectResult};
|
use crate::error::{ProjectError, ProjectResult};
|
||||||
use crate::interpreter::HandlerTable;
|
use crate::interpreter::HandlerTable;
|
||||||
use crate::rule::Repo;
|
use crate::rule::Repo;
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast, ast_to_interpreted, collect_consts, collect_rules, rule, Interner,
|
ast, ast_to_interpreted, collect_consts, collect_rules, rule, Interner,
|
||||||
Location, ProjectTree, Sym,
|
Location, ProjectTree, Sym,
|
||||||
@@ -128,7 +126,7 @@ impl ProjectError for MacroTimeout {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
self.location.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
|
||||||
use crate::error::{ErrorPosition, ProjectError, ProjectResult};
|
use crate::error::{ProjectError, ProjectResult};
|
||||||
use crate::interpreted::{self, ExprInst};
|
use crate::interpreted::{self, ExprInst};
|
||||||
#[allow(unused)] // for doc
|
#[allow(unused)] // for doc
|
||||||
use crate::interpreter;
|
use crate::interpreter;
|
||||||
use crate::interpreter::{
|
use crate::interpreter::{
|
||||||
run_handler, Context, HandlerTable, Return, RuntimeError,
|
run_handler, Context, HandlerTable, Return, RuntimeError,
|
||||||
};
|
};
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
|
||||||
use crate::{Interner, Location, Sym};
|
use crate::{Interner, Location, Sym};
|
||||||
|
|
||||||
/// This struct ties the state of systems to loaded code, and allows to call
|
/// This struct ties the state of systems to loaded code, and allows to call
|
||||||
@@ -84,7 +82,7 @@ impl ProjectError for MissingSymbol {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
self.location.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ use crate::Primitive;
|
|||||||
/// ```
|
/// ```
|
||||||
/// use orchidlang::{Literal};
|
/// use orchidlang::{Literal};
|
||||||
/// use orchidlang::interpreted::ExprInst;
|
/// use orchidlang::interpreted::ExprInst;
|
||||||
/// use orchidlang::stl::litconv::with_lit;
|
/// use orchidlang::systems::cast_exprinst::with_lit;
|
||||||
/// use orchidlang::{atomic_impl, atomic_redirect, externfn_impl};
|
/// use orchidlang::{atomic_impl, atomic_redirect, externfn_impl};
|
||||||
///
|
///
|
||||||
/// /// Convert a literal to a string using Rust's conversions for floats, chars and
|
/// /// Convert a literal to a string using Rust's conversions for floats, chars and
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ use crate::write_fn_step;
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use orchidlang::interpreted::Clause;
|
/// use orchidlang::interpreted::Clause;
|
||||||
/// use orchidlang::stl::litconv::with_str;
|
/// use orchidlang::systems::cast_exprinst::with_str;
|
||||||
/// use orchidlang::{define_fn, Literal, Primitive};
|
/// use orchidlang::{define_fn, Literal, Primitive};
|
||||||
///
|
///
|
||||||
/// define_fn! {expr=x in
|
/// define_fn! {expr=x in
|
||||||
@@ -58,7 +58,7 @@ use crate::write_fn_step;
|
|||||||
/// A simpler format is also offered for unary functions:
|
/// A simpler format is also offered for unary functions:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use orchidlang::stl::litconv::with_lit;
|
/// use orchidlang::systems::cast_exprinst::with_lit;
|
||||||
/// use orchidlang::{define_fn, Literal};
|
/// use orchidlang::{define_fn, Literal};
|
||||||
///
|
///
|
||||||
/// define_fn! {
|
/// define_fn! {
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ use crate::interpreted::ExprInst;
|
|||||||
/// discussed below. The newly bound names (here `s` and `i` before `=`) can
|
/// discussed below. The newly bound names (here `s` and `i` before `=`) can
|
||||||
/// also receive type annotations.
|
/// also receive type annotations.
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```
|
||||||
/// // FIXME this is a very old example that wouldn't compile now
|
/// // FIXME this is a very old example that wouldn't compile now
|
||||||
/// use unicode_segmentation::UnicodeSegmentation;
|
/// use unicode_segmentation::UnicodeSegmentation;
|
||||||
///
|
///
|
||||||
/// use orchidlang::{write_fn_step, Literal, Primitive};
|
/// use orchidlang::{write_fn_step, Literal, Primitive};
|
||||||
/// use orchidlang::interpreted::Clause;
|
/// use orchidlang::interpreted::Clause;
|
||||||
/// use orchidlang::stl::litconv::{with_str, with_uint};
|
/// use orchidlang::systems::cast_exprinst::{with_str, with_uint};
|
||||||
/// use orchidlang::stl::RuntimeError;
|
/// use orchidlang::systems::RuntimeError;
|
||||||
///
|
///
|
||||||
/// // Initial state
|
/// // Initial state
|
||||||
/// write_fn_step!(pub CharAt2 > CharAt1);
|
/// write_fn_step!(pub CharAt2 > CharAt1);
|
||||||
@@ -40,7 +40,7 @@ use crate::interpreted::ExprInst;
|
|||||||
/// i = x => with_uint(x, Ok);
|
/// i = x => with_uint(x, Ok);
|
||||||
/// {
|
/// {
|
||||||
/// if let Some(c) = s.graphemes(true).nth(*i as usize) {
|
/// if let Some(c) = s.graphemes(true).nth(*i as usize) {
|
||||||
/// Ok(Literal::Char(c.to_string()).into())
|
/// Ok(Literal::Str(c.to_string()).into())
|
||||||
/// } else {
|
/// } else {
|
||||||
/// RuntimeError::fail(
|
/// RuntimeError::fail(
|
||||||
/// "Character index out of bounds".to_string(),
|
/// "Character index out of bounds".to_string(),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::mem;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
@@ -8,7 +7,6 @@ use trait_set::trait_set;
|
|||||||
use super::{run, Context, Return, RuntimeError};
|
use super::{run, Context, Return, RuntimeError};
|
||||||
use crate::foreign::ExternError;
|
use crate::foreign::ExternError;
|
||||||
use crate::interpreted::{Clause, ExprInst};
|
use crate::interpreted::{Clause, ExprInst};
|
||||||
use crate::utils::unwrap_or;
|
|
||||||
use crate::Primitive;
|
use crate::Primitive;
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
@@ -65,20 +63,15 @@ pub fn run_handler(
|
|||||||
) -> Result<Return, RuntimeError> {
|
) -> Result<Return, RuntimeError> {
|
||||||
loop {
|
loop {
|
||||||
let ret = run(expr.clone(), ctx.clone())?;
|
let ret = run(expr.clone(), ctx.clone())?;
|
||||||
if ret.gas == Some(0) {
|
if let Clause::P(Primitive::Atom(a)) = &ret.state.expr().clause {
|
||||||
return Ok(ret);
|
if let Some(e) = handlers.dispatch(a.0.as_any()) {
|
||||||
}
|
expr = e?;
|
||||||
let state_ex = ret.state.expr();
|
|
||||||
let a = if let Clause::P(Primitive::Atom(a)) = &state_ex.clause {
|
|
||||||
a
|
|
||||||
} else {
|
|
||||||
mem::drop(state_ex);
|
|
||||||
return Ok(ret);
|
|
||||||
};
|
|
||||||
expr = unwrap_or!(handlers.dispatch(a.0.as_any()); {
|
|
||||||
mem::drop(state_ex);
|
|
||||||
return Ok(ret)
|
|
||||||
})?;
|
|
||||||
ctx.gas = ret.gas;
|
ctx.gas = ret.gas;
|
||||||
|
if ret.gas.map_or(true, |g| g > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,4 +34,4 @@ pub use representations::{
|
|||||||
ast, from_const_tree, interpreted, sourcefile, tree, ConstTree, Literal,
|
ast, from_const_tree, interpreted, sourcefile, tree, ConstTree, Literal,
|
||||||
Location, PathSet, Primitive,
|
Location, PathSet, Primitive,
|
||||||
};
|
};
|
||||||
pub use utils::{Side, Substack, ThreadPool};
|
pub use utils::{thread_pool, Side, Substack};
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use itertools::Itertools;
|
|||||||
use super::{Entry, Lexeme};
|
use super::{Entry, Lexeme};
|
||||||
use crate::error::{ErrorPosition, ProjectError};
|
use crate::error::{ErrorPosition, ProjectError};
|
||||||
use crate::interner::InternedDisplay;
|
use crate::interner::InternedDisplay;
|
||||||
use crate::utils::iter::box_once;
|
|
||||||
use crate::utils::BoxedIter;
|
use crate::utils::BoxedIter;
|
||||||
use crate::{Interner, Location, Tok};
|
use crate::{Interner, Location, Tok};
|
||||||
|
|
||||||
@@ -21,8 +20,8 @@ impl ProjectError for LineNeedsPrefix {
|
|||||||
fn message(&self, i: &Interner) -> String {
|
fn message(&self, i: &Interner) -> String {
|
||||||
format!("{} cannot appear at the beginning of a line", self.entry.bundle(i))
|
format!("{} cannot appear at the beginning of a line", self.entry.bundle(i))
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { message: None, location: self.entry.location() })
|
self.entry.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +41,8 @@ impl ProjectError for UnexpectedEOL {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { message: None, location: self.entry.location() })
|
self.entry.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,8 +53,8 @@ impl ProjectError for ExpectedEOL {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Expected the end of the line"
|
"Expected the end of the line"
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
self.location.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +86,8 @@ impl ProjectError for ExpectedName {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.entry.location(), message: None })
|
self.entry.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,8 +125,9 @@ impl ProjectError for Expected {
|
|||||||
let or_name = if self.or_name { " or a name" } else { "" };
|
let or_name = if self.or_name { " or a name" } else { "" };
|
||||||
format!("Expected {}{} but found {}", list, or_name, self.found.bundle(i))
|
format!("Expected {}{} but found {}", list, or_name, self.found.bundle(i))
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
|
||||||
box_once(ErrorPosition { location: self.found.location(), message: None })
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
|
self.found.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,8 +143,8 @@ impl ProjectError for ReservedToken {
|
|||||||
format!("{} is a reserved token", self.entry.bundle(i))
|
format!("{} is a reserved token", self.entry.bundle(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.entry.location(), message: None })
|
self.entry.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,8 +161,8 @@ impl ProjectError for BadTokenInRegion {
|
|||||||
format!("{} cannot appear in {}", self.entry.bundle(i), self.region)
|
format!("{} cannot appear in {}", self.entry.bundle(i), self.region)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.entry.location(), message: None })
|
self.entry.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,8 +179,8 @@ impl ProjectError for NotFound {
|
|||||||
format!("{} was expected", self.expected)
|
format!("{} was expected", self.expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
self.location.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +191,8 @@ impl ProjectError for LeadingNS {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
":: can only follow a name token"
|
":: can only follow a name token"
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
self.location.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,8 +206,8 @@ impl ProjectError for MisalignedParen {
|
|||||||
fn message(&self, i: &Interner) -> String {
|
fn message(&self, i: &Interner) -> String {
|
||||||
format!("This {} has no pair", self.entry.bundle(i))
|
format!("This {} has no pair", self.entry.bundle(i))
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.entry.location(), message: None })
|
self.entry.location()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,8 +218,20 @@ impl ProjectError for NamespacedExport {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Exports can only refer to unnamespaced names in the local namespace"
|
"Exports can only refer to unnamespaced names in the local namespace"
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
self.location.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GlobExport {
|
||||||
|
pub location: Location,
|
||||||
|
}
|
||||||
|
impl ProjectError for GlobExport {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"Exports can only refer to concrete names, globstars are not allowed"
|
||||||
|
}
|
||||||
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
|
self.location.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,45 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use super::context::Context;
|
use super::context::Context;
|
||||||
use super::errors::{Expected, ExpectedName};
|
use super::errors::Expected;
|
||||||
use super::stream::Stream;
|
use super::stream::Stream;
|
||||||
use super::Lexeme;
|
use super::Lexeme;
|
||||||
use crate::error::{ProjectError, ProjectResult};
|
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;
|
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(
|
fn parse_multiname_branch(
|
||||||
cursor: Stream<'_>,
|
cursor: Stream<'_>,
|
||||||
ctx: impl Context,
|
ctx: impl Context,
|
||||||
) -> ProjectResult<(BoxedIterIter<Tok<String>>, Stream<'_>)> {
|
) -> ProjectResult<(BoxedIter<Subresult>, Stream<'_>)> {
|
||||||
let comma = ctx.interner().i(",");
|
let comma = ctx.interner().i(",");
|
||||||
let (subnames, cursor) = parse_multiname_rec(cursor, ctx.clone())?;
|
let (subnames, cursor) = parse_multiname_rec(cursor, ctx.clone())?;
|
||||||
let (delim, cursor) = cursor.trim().pop()?;
|
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<'_>,
|
curosr: Stream<'_>,
|
||||||
ctx: impl Context,
|
ctx: impl Context,
|
||||||
) -> ProjectResult<(BoxedIterIter<Tok<String>>, Stream<'_>)> {
|
) -> ProjectResult<(BoxedIter<Subresult>, Stream<'_>)> {
|
||||||
|
let star = ctx.interner().i("*");
|
||||||
let comma = ctx.interner().i(",");
|
let comma = ctx.interner().i(",");
|
||||||
let (head, cursor) = curosr.trim().pop()?;
|
let (head, mut cursor) = curosr.trim().pop()?;
|
||||||
match &head.lexeme {
|
match &head.lexeme {
|
||||||
Lexeme::LP('(') => parse_multiname_branch(cursor, ctx),
|
Lexeme::LP('(') => parse_multiname_branch(cursor, ctx),
|
||||||
Lexeme::LP('[') => {
|
Lexeme::LP('[') => {
|
||||||
let (op_ent, cursor) = cursor.trim().pop()?;
|
let mut names = Vec::new();
|
||||||
let op = ExpectedName::expect(op_ent)?;
|
loop {
|
||||||
let (rp_ent, cursor) = cursor.trim().pop()?;
|
let head;
|
||||||
Expected::expect(Lexeme::RP('['), rp_ent)?;
|
(head, cursor) = cursor.trim().pop()?;
|
||||||
Ok((box_once(box_once(op)), cursor))
|
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());
|
||||||
},
|
},
|
||||||
Lexeme::Name(n) if *n != comma => {
|
}
|
||||||
|
}
|
||||||
|
Ok((Box::new(names.into_iter().map(Subresult::new_named)), cursor))
|
||||||
|
},
|
||||||
|
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();
|
let cursor = cursor.trim();
|
||||||
if cursor.get(0).ok().map(|e| &e.lexeme) == Some(&Lexeme::NS) {
|
if cursor.get(0).ok().map(|e| &e.lexeme) == Some(&Lexeme::NS) {
|
||||||
let cursor = cursor.step()?;
|
let cursor = cursor.step()?;
|
||||||
let (out, cursor) = parse_multiname_rec(cursor, ctx)?;
|
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))
|
Ok((out, cursor))
|
||||||
} else {
|
} else {
|
||||||
Ok((box_once(box_once(*n)), cursor))
|
Ok((box_once(Subresult::new_named(*n)), cursor))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => Err(
|
_ => Err(
|
||||||
@@ -73,16 +116,7 @@ pub fn parse_multiname_rec(
|
|||||||
pub fn parse_multiname(
|
pub fn parse_multiname(
|
||||||
cursor: Stream<'_>,
|
cursor: Stream<'_>,
|
||||||
ctx: impl Context,
|
ctx: impl Context,
|
||||||
) -> ProjectResult<(Vec<Vec<Tok<String>>>, Stream<'_>)> {
|
) -> ProjectResult<(Vec<Import>, Stream<'_>)> {
|
||||||
let (output, cont) = parse_multiname_rec(cursor, ctx)?;
|
let (output, cont) = parse_multiname_rec(cursor, ctx)?;
|
||||||
let output = output
|
Ok((output.map(|sr| sr.finalize()).collect(), cont))
|
||||||
.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))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use itertools::Itertools;
|
|||||||
|
|
||||||
use super::context::Context;
|
use super::context::Context;
|
||||||
use super::errors::{
|
use super::errors::{
|
||||||
BadTokenInRegion, Expected, ExpectedName, LeadingNS, MisalignedParen,
|
BadTokenInRegion, Expected, ExpectedName, GlobExport, LeadingNS,
|
||||||
NamespacedExport, ReservedToken, UnexpectedEOL,
|
MisalignedParen, NamespacedExport, ReservedToken, UnexpectedEOL,
|
||||||
};
|
};
|
||||||
use super::lexer::Lexeme;
|
use super::lexer::Lexeme;
|
||||||
use super::multiname::parse_multiname;
|
use super::multiname::parse_multiname;
|
||||||
@@ -71,18 +71,8 @@ pub fn parse_line(
|
|||||||
Lexeme::Const | Lexeme::Macro | Lexeme::Module =>
|
Lexeme::Const | Lexeme::Macro | Lexeme::Module =>
|
||||||
Ok(FileEntry::Internal(parse_member(cursor, ctx)?)),
|
Ok(FileEntry::Internal(parse_member(cursor, ctx)?)),
|
||||||
Lexeme::Import => {
|
Lexeme::Import => {
|
||||||
let globstar = ctx.interner().i("*");
|
let (imports, cont) = parse_multiname(cursor.step()?, ctx)?;
|
||||||
let (names, cont) = parse_multiname(cursor.step()?, ctx.clone())?;
|
|
||||||
cont.expect_empty()?;
|
cont.expect_empty()?;
|
||||||
let imports = (names.into_iter())
|
|
||||||
.map(|mut nsname| {
|
|
||||||
let name = nsname.pop().expect("multinames cannot be zero-length");
|
|
||||||
Import {
|
|
||||||
path: ctx.interner().i(&nsname),
|
|
||||||
name: if name == globstar { None } else { Some(name) },
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
Ok(FileEntry::Import(imports))
|
Ok(FileEntry::Import(imports))
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
@@ -105,9 +95,12 @@ pub fn parse_export_line(
|
|||||||
let (names, cont) = parse_multiname(cursor.step()?, ctx)?;
|
let (names, cont) = parse_multiname(cursor.step()?, ctx)?;
|
||||||
cont.expect_empty()?;
|
cont.expect_empty()?;
|
||||||
let names = (names.into_iter())
|
let names = (names.into_iter())
|
||||||
.map(|i| if i.len() == 1 { Some(i[0]) } else { None })
|
.map(|Import { name, path }| match (name, &path[..]) {
|
||||||
.collect::<Option<Vec<_>>>()
|
(Some(n), []) => Ok(n),
|
||||||
.ok_or_else(|| NamespacedExport { location: cursor.location() }.rc())?;
|
(None, _) => Err(GlobExport { location: cursor.location() }.rc()),
|
||||||
|
_ => Err(NamespacedExport { location: cursor.location() }.rc()),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
Ok(FileEntry::Export(names))
|
Ok(FileEntry::Export(names))
|
||||||
},
|
},
|
||||||
Lexeme::Const | Lexeme::Macro | Lexeme::Module =>
|
Lexeme::Const | Lexeme::Macro | Lexeme::Module =>
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ use std::{fs, io};
|
|||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use rust_embed::RustEmbed;
|
use rust_embed::RustEmbed;
|
||||||
|
|
||||||
use crate::error::{ErrorPosition, ProjectError, ProjectResult};
|
use crate::error::{ProjectError, ProjectResult};
|
||||||
#[allow(unused)] // for doc
|
#[allow(unused)] // for doc
|
||||||
use crate::facade::System;
|
use crate::facade::System;
|
||||||
use crate::interner::Interner;
|
use crate::interner::Interner;
|
||||||
use crate::utils::iter::box_once;
|
use crate::utils::Cache;
|
||||||
use crate::utils::{BoxedIter, Cache};
|
use crate::{Location, Stok, VName};
|
||||||
use crate::{Stok, VName};
|
|
||||||
|
|
||||||
/// All the data available about a failed source load call
|
/// All the data available about a failed source load call
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -25,8 +24,8 @@ impl ProjectError for FileLoadingError {
|
|||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"Neither a file nor a directory could be read from the requested path"
|
"Neither a file nor a directory could be read from the requested path"
|
||||||
}
|
}
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
fn one_position(&self, _i: &Interner) -> crate::Location {
|
||||||
box_once(ErrorPosition::just_file(self.path.clone()))
|
Location::File(Rc::new(self.path.clone()))
|
||||||
}
|
}
|
||||||
fn message(&self, _i: &Interner) -> String {
|
fn message(&self, _i: &Interner) -> String {
|
||||||
format!("File: {}\nDirectory: {}", self.file, self.dir)
|
format!("File: {}\nDirectory: {}", self.file, self.dir)
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ fn assert_visible(
|
|||||||
target: &[Tok<String>], // may point to a symbol or module of any kind
|
target: &[Tok<String>], // may point to a symbol or module of any kind
|
||||||
project: &ProjectTree<VName>,
|
project: &ProjectTree<VName>,
|
||||||
) -> ProjectResult<()> {
|
) -> ProjectResult<()> {
|
||||||
let (tgt_item, tgt_path) = unwrap_or!(target.split_last(); return Ok(()));
|
let (tgt_item, tgt_path) = unwrap_or! {
|
||||||
|
target.split_last();
|
||||||
|
return Ok(())
|
||||||
|
};
|
||||||
let shared_len =
|
let shared_len =
|
||||||
source.iter().zip(tgt_path.iter()).take_while(|(a, b)| a == b).count();
|
source.iter().zip(tgt_path.iter()).take_while(|(a, b)| a == b).count();
|
||||||
let vis_ignored_len = usize::min(tgt_path.len(), shared_len + 1);
|
let vis_ignored_len = usize::min(tgt_path.len(), shared_len + 1);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ fn source_to_module(
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let imports_from = (imports.iter())
|
let imports_from = (imports.iter())
|
||||||
.map(|imp| -> ProjectResult<_> {
|
.map(|imp| -> ProjectResult<_> {
|
||||||
let mut imp_path_v = i.r(imp.path).clone();
|
let mut imp_path_v = imp.path.clone();
|
||||||
imp_path_v.push(imp.name.expect("glob imports had just been resolved"));
|
imp_path_v.push(imp.name.expect("glob imports had just been resolved"));
|
||||||
let mut abs_path = absolute_path(&path_v, &imp_path_v, i)
|
let mut abs_path = absolute_path(&path_v, &imp_path_v, i)
|
||||||
.expect("should have failed in preparsing");
|
.expect("should have failed in preparsing");
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::error::{NotFound, ProjectError, ProjectResult};
|
|||||||
use crate::interner::{Interner, Tok};
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::pipeline::source_loader::LoadedSourceTable;
|
use crate::pipeline::source_loader::LoadedSourceTable;
|
||||||
use crate::representations::tree::WalkErrorKind;
|
use crate::representations::tree::WalkErrorKind;
|
||||||
use crate::utils::{split_max_prefix, unwrap_or, Cache};
|
use crate::utils::{split_max_prefix, Cache};
|
||||||
use crate::Sym;
|
use crate::Sym;
|
||||||
|
|
||||||
pub type OpsResult = ProjectResult<Rc<HashSet<Tok<String>>>>;
|
pub type OpsResult = ProjectResult<Rc<HashSet<Tok<String>>>>;
|
||||||
@@ -33,9 +33,9 @@ pub fn collect_exported_ops(
|
|||||||
) -> OpsResult {
|
) -> OpsResult {
|
||||||
let injected = injected(path).unwrap_or_else(|| Rc::new(HashSet::new()));
|
let injected = injected(path).unwrap_or_else(|| Rc::new(HashSet::new()));
|
||||||
let path_s = &i.r(path)[..];
|
let path_s = &i.r(path)[..];
|
||||||
let name_split = split_max_prefix(path_s, &|n| loaded.contains_key(n));
|
match split_max_prefix(path_s, &|n| loaded.contains_key(n)) {
|
||||||
let (fpath, subpath) = unwrap_or!(name_split; return Ok(Rc::new(
|
None => {
|
||||||
(loaded.keys())
|
let ops = (loaded.keys())
|
||||||
.filter_map(|modname| {
|
.filter_map(|modname| {
|
||||||
if path_s.len() == coprefix(path_s.iter(), modname.iter()) {
|
if path_s.len() == coprefix(path_s.iter(), modname.iter()) {
|
||||||
Some(modname[path_s.len()])
|
Some(modname[path_s.len()])
|
||||||
@@ -44,11 +44,12 @@ pub fn collect_exported_ops(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.chain(injected.iter().copied())
|
.chain(injected.iter().copied())
|
||||||
.collect::<HashSet<_>>(),
|
.collect::<HashSet<_>>();
|
||||||
)));
|
Ok(Rc::new(ops))
|
||||||
|
},
|
||||||
|
Some((fpath, subpath)) => {
|
||||||
let preparsed = &loaded[fpath].preparsed;
|
let preparsed = &loaded[fpath].preparsed;
|
||||||
let module =
|
let module = preparsed.0.walk_ref(subpath, false).map_err(
|
||||||
preparsed.0.walk_ref(subpath, false).map_err(
|
|
||||||
|walk_err| match walk_err.kind {
|
|walk_err| match walk_err.kind {
|
||||||
WalkErrorKind::Private => {
|
WalkErrorKind::Private => {
|
||||||
unreachable!("visibility is not being checked here")
|
unreachable!("visibility is not being checked here")
|
||||||
@@ -67,6 +68,8 @@ pub fn collect_exported_ops(
|
|||||||
.chain(injected.iter().copied())
|
.chain(injected.iter().copied())
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
Ok(Rc::new(out))
|
Ok(Rc::new(out))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mk_cache<'a>(
|
pub fn mk_cache<'a>(
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ pub fn collect_ops_for(
|
|||||||
ret.insert(n);
|
ret.insert(n);
|
||||||
} else {
|
} else {
|
||||||
let path = i.expect(
|
let path = i.expect(
|
||||||
import_abs_path(file, modpath, &i.r(import.path)[..], i),
|
import_abs_path(file, modpath, &import.path, i),
|
||||||
"This error should have been caught during loading",
|
"This error should have been caught during loading",
|
||||||
);
|
);
|
||||||
ret.extend(ops_cache.find(&i.i(&path))?.iter().copied());
|
ret.extend(ops_cache.find(&i.i(&path))?.iter().copied());
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ fn entv_rec(
|
|||||||
.flat_map(|import| {
|
.flat_map(|import| {
|
||||||
if let Import { name: None, path } = import {
|
if let Import { name: None, path } = import {
|
||||||
let p = i.expect(
|
let p = i.expect(
|
||||||
import_abs_path(mod_path, mod_stack, &i.r(path)[..], i),
|
import_abs_path(mod_path, mod_stack, &path, i),
|
||||||
"Should have emerged in preparsing",
|
"Should have emerged in preparsing",
|
||||||
);
|
);
|
||||||
let names = i.expect(
|
let names = i.expect(
|
||||||
@@ -67,7 +67,7 @@ fn entv_rec(
|
|||||||
"Should have emerged in second parsing",
|
"Should have emerged in second parsing",
|
||||||
);
|
);
|
||||||
let imports = (names.iter())
|
let imports = (names.iter())
|
||||||
.map(move |&n| Import { name: Some(n), path })
|
.map(|&n| Import { name: Some(n), path: path.clone() })
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
Box::new(imports.into_iter()) as BoxedIter<Import>
|
Box::new(imports.into_iter()) as BoxedIter<Import>
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ fn load_abs_path_rec(
|
|||||||
// recurse on all imported modules
|
// recurse on all imported modules
|
||||||
preparsed.0.visit_all_imports(&mut |modpath, _module, import| {
|
preparsed.0.visit_all_imports(&mut |modpath, _module, import| {
|
||||||
let abs_pathv =
|
let abs_pathv =
|
||||||
import_abs_path(filename, modpath, &import.nonglob_path(i), i)?;
|
import_abs_path(filename, modpath, &import.nonglob_path(), i)?;
|
||||||
if abs_path.starts_with(&abs_pathv) {
|
if abs_path.starts_with(&abs_pathv) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use super::location::Location;
|
use super::location::Location;
|
||||||
use super::{ast, postmacro};
|
use super::{ast, postmacro};
|
||||||
use crate::error::{ErrorPosition, ProjectError};
|
use crate::error::ProjectError;
|
||||||
use crate::utils::iter::box_once;
|
use crate::utils::Substack;
|
||||||
use crate::utils::{BoxedIter, Substack};
|
|
||||||
use crate::{Interner, Sym};
|
use crate::{Interner, Sym};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -51,9 +50,8 @@ impl ProjectError for Error {
|
|||||||
_ => self.description().to_string(),
|
_ => self.description().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn one_position(&self, _i: &Interner) -> Location {
|
||||||
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
|
self.location.clone()
|
||||||
box_once(ErrorPosition { location: self.location.clone(), message: None })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ use super::namelike::VName;
|
|||||||
use crate::ast::{Constant, Rule};
|
use crate::ast::{Constant, Rule};
|
||||||
use crate::interner::{Interner, Tok};
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::utils::{unwrap_or, BoxedIter};
|
use crate::utils::{unwrap_or, BoxedIter};
|
||||||
use crate::Sym;
|
|
||||||
|
|
||||||
/// An import pointing at another module, either specifying the symbol to be
|
/// An import pointing at another module, either specifying the symbol to be
|
||||||
/// imported or importing all available symbols with a globstar (*)
|
/// imported or importing all available symbols with a globstar (*)
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
/// Import path, a sequence of module names. Can either start with
|
/// Import path, a sequence of module names. Can either start with
|
||||||
///
|
///
|
||||||
@@ -19,7 +18,7 @@ pub struct Import {
|
|||||||
/// - any number of `super` to reference the parent module of the implied
|
/// - any number of `super` to reference the parent module of the implied
|
||||||
/// `self`
|
/// `self`
|
||||||
/// - a root name
|
/// - a root name
|
||||||
pub path: Sym,
|
pub path: VName,
|
||||||
/// If name is None, this is a wildcard import
|
/// If name is None, this is a wildcard import
|
||||||
pub name: Option<Tok<String>>,
|
pub name: Option<Tok<String>>,
|
||||||
}
|
}
|
||||||
@@ -29,8 +28,8 @@ impl Import {
|
|||||||
///
|
///
|
||||||
/// Returns the path if this is a glob import, or the path plus the
|
/// Returns the path if this is a glob import, or the path plus the
|
||||||
/// name if this is a specific import
|
/// name if this is a specific import
|
||||||
pub fn nonglob_path(&self, i: &Interner) -> Vec<Tok<String>> {
|
pub fn nonglob_path(&self) -> Vec<Tok<String>> {
|
||||||
let mut path_vec = i.r(self.path).clone();
|
let mut path_vec = self.path.clone();
|
||||||
if let Some(n) = self.name {
|
if let Some(n) = self.name {
|
||||||
path_vec.push(n)
|
path_vec.push(n)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ impl<'a, P: MessagePort, ST: StreamTable + 'a> IntoSystem<'a>
|
|||||||
constants: io_bindings(i, streams).unwrap_tree(),
|
constants: io_bindings(i, streams).unwrap_tree(),
|
||||||
code: embed_to_map::<IOEmbed>(".orc", i),
|
code: embed_to_map::<IOEmbed>(".orc", i),
|
||||||
prelude: vec![FileEntry::Import(vec![Import {
|
prelude: vec![FileEntry::Import(vec![Import {
|
||||||
path: i.i(&vec![i.i("system"), i.i("io"), i.i("prelude")]),
|
path: vec![i.i("system"), i.i("io"), i.i("prelude")],
|
||||||
name: None,
|
name: None,
|
||||||
}])],
|
}])],
|
||||||
handlers,
|
handlers,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use hashbrown::HashMap;
|
|||||||
|
|
||||||
use crate::foreign::ExternError;
|
use crate::foreign::ExternError;
|
||||||
use crate::systems::asynch::MessagePort;
|
use crate::systems::asynch::MessagePort;
|
||||||
use crate::utils::{take_with_output, Task};
|
use crate::thread_pool::{Task, ThreadPool};
|
||||||
use crate::ThreadPool;
|
use crate::utils::take_with_output;
|
||||||
|
|
||||||
pub trait StreamHandle: Clone + Send {
|
pub trait StreamHandle: Clone + Send {
|
||||||
fn new(id: usize) -> Self;
|
fn new(id: usize) -> Self;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import std::num::*
|
import std::num::*
|
||||||
export ::(+, -, *, /, %)
|
export ::[+ - * / %]
|
||||||
import std::str::*
|
import std::str::*
|
||||||
export ::[++]
|
export ::[++]
|
||||||
import std::bool::*
|
import std::bool::*
|
||||||
export ::(==, if, then, else, true, false)
|
export ::([==], if, then, else, true, false)
|
||||||
import std::fn::*
|
import std::fn::*
|
||||||
export ::($, |>, =>, identity, pass, pass2, return)
|
export ::([$ |> =>], identity, pass, pass2, return)
|
||||||
import std::list
|
import std::list
|
||||||
import std::map
|
import std::map
|
||||||
import std::option
|
import std::option
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ impl IntoSystem<'static> for StlConfig {
|
|||||||
constants: HashMap::from([(i.i("std"), fns)]),
|
constants: HashMap::from([(i.i("std"), fns)]),
|
||||||
code: embed_to_map::<StlEmbed>(".orc", i),
|
code: embed_to_map::<StlEmbed>(".orc", i),
|
||||||
prelude: vec![FileEntry::Import(vec![Import {
|
prelude: vec![FileEntry::Import(vec![Import {
|
||||||
path: i.i(&[i.i("std"), i.i("prelude")][..]),
|
path: vec![i.i("std"), i.i("prelude")],
|
||||||
name: None,
|
name: None,
|
||||||
}])],
|
}])],
|
||||||
handlers: HandlerTable::new(),
|
handlers: HandlerTable::new(),
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ use std::iter;
|
|||||||
/// A trait object of [Iterator] to be assigned to variables that may be
|
/// A trait object of [Iterator] to be assigned to variables that may be
|
||||||
/// initialized form multiple iterators of incompatible types
|
/// initialized form multiple iterators of incompatible types
|
||||||
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
|
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
|
||||||
/// A [BoxedIter] of [BoxedIter].
|
|
||||||
pub type BoxedIterIter<'a, T> = BoxedIter<'a, BoxedIter<'a, T>>;
|
|
||||||
/// creates a [BoxedIter] of a single element
|
/// creates a [BoxedIter] of a single element
|
||||||
pub fn box_once<'a, T: 'a>(t: T) -> BoxedIter<'a, T> {
|
pub fn box_once<'a, T: 'a>(t: T) -> BoxedIter<'a, T> {
|
||||||
Box::new(iter::once(t))
|
Box::new(iter::once(t))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ mod split_max_prefix;
|
|||||||
mod string_from_charset;
|
mod string_from_charset;
|
||||||
mod substack;
|
mod substack;
|
||||||
mod take_with_output;
|
mod take_with_output;
|
||||||
mod thread_pool;
|
pub mod thread_pool;
|
||||||
mod unwrap_or;
|
mod unwrap_or;
|
||||||
|
|
||||||
pub use cache::Cache;
|
pub use cache::Cache;
|
||||||
@@ -30,4 +30,3 @@ pub use iter::BoxedIter;
|
|||||||
pub use iter_find::iter_find;
|
pub use iter_find::iter_find;
|
||||||
pub use string_from_charset::string_from_charset;
|
pub use string_from_charset::string_from_charset;
|
||||||
pub use take_with_output::take_with_output;
|
pub use take_with_output::take_with_output;
|
||||||
pub use thread_pool::{Query, QueryTask, Task, ThreadPool};
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
//! A thread pool for executing tasks in parallel, spawning threads as workload
|
||||||
|
//! increases and terminating them as tasks finish. This is not terribly
|
||||||
|
//! efficient, its main design goal is to parallelize blocking I/O calls.
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc::{sync_channel, SyncSender};
|
use std::sync::mpsc::{sync_channel, SyncSender};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -6,6 +10,8 @@ use std::thread::spawn;
|
|||||||
/// A trait for a task dispatched on a [ThreadPool]. The task owns all relevant
|
/// A trait for a task dispatched on a [ThreadPool]. The task owns all relevant
|
||||||
/// data, is safe to pass between threads and is executed only once.
|
/// data, is safe to pass between threads and is executed only once.
|
||||||
pub trait Task: Send + 'static {
|
pub trait Task: Send + 'static {
|
||||||
|
/// Execute the task. At a minimum, this involves signaling some other thread,
|
||||||
|
/// otherwise the task has no effect.
|
||||||
fn run(self);
|
fn run(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,10 +21,21 @@ impl<F: FnOnce() + Send + 'static> Task for F {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An async unit of work that produces some result, see [Task]. This can be
|
||||||
|
/// wrapped in a generic reporter to create a task.
|
||||||
pub trait Query: Send + 'static {
|
pub trait Query: Send + 'static {
|
||||||
|
/// The value produced by the query
|
||||||
type Result: Send + 'static;
|
type Result: Send + 'static;
|
||||||
|
|
||||||
|
/// Execute the query, producing some value which can then be sent to another
|
||||||
|
/// thread
|
||||||
fn run(self) -> Self::Result;
|
fn run(self) -> Self::Result;
|
||||||
|
|
||||||
|
/// Associate the query with a reporter expressed in a plain function.
|
||||||
|
/// Note that because every lambda has a distinct type and every thread pool
|
||||||
|
/// runs exactly one type of task, this can appear only once in the code for
|
||||||
|
/// a given thread pool. It is practical in a narrow set of cases, most of the
|
||||||
|
/// time however you are better off defining an explicit reporter.
|
||||||
fn then<F: FnOnce(Self::Result) + Send + 'static>(
|
fn then<F: FnOnce(Self::Result) + Send + 'static>(
|
||||||
self,
|
self,
|
||||||
callback: F,
|
callback: F,
|
||||||
@@ -37,6 +54,8 @@ impl<F: FnOnce() -> R + Send + 'static, R: Send + 'static> Query for F {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A reporter that calls a statically known function with the result of a
|
||||||
|
/// query. Constructed with [Query::then]
|
||||||
pub struct QueryTask<Q: Query, F: FnOnce(Q::Result) + Send + 'static> {
|
pub struct QueryTask<Q: Query, F: FnOnce(Q::Result) + Send + 'static> {
|
||||||
query: Q,
|
query: Q,
|
||||||
callback: F,
|
callback: F,
|
||||||
@@ -68,16 +87,23 @@ struct ThreadPoolData<T: Task> {
|
|||||||
/// arrive. To get rid of the last waiting thread, drop the thread pool.
|
/// arrive. To get rid of the last waiting thread, drop the thread pool.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use orchidlang::ThreadPool;
|
/// use orchidlang::thread_pool::{Task, ThreadPool};
|
||||||
///
|
///
|
||||||
/// let pool = ThreadPool::new(|s: String, _| println!("{}", s));
|
/// struct MyTask(&'static str);
|
||||||
|
/// impl Task for MyTask {
|
||||||
|
/// fn run(self) {
|
||||||
|
/// println!("{}", self.0)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let pool = ThreadPool::new();
|
||||||
///
|
///
|
||||||
/// // spawns first thread
|
/// // spawns first thread
|
||||||
/// pool.submit("foo".to_string());
|
/// pool.submit(MyTask("foo"));
|
||||||
/// // probably spawns second thread
|
/// // probably spawns second thread
|
||||||
/// pool.submit("bar".to_string());
|
/// pool.submit(MyTask("bar"));
|
||||||
/// // either spawns third thread or reuses first
|
/// // either spawns third thread or reuses first
|
||||||
/// pool.submit("baz".to_string());
|
/// pool.submit(MyTask("baz"));
|
||||||
/// ```
|
/// ```
|
||||||
pub struct ThreadPool<T: Task> {
|
pub struct ThreadPool<T: Task> {
|
||||||
data: Arc<ThreadPoolData<T>>,
|
data: Arc<ThreadPoolData<T>>,
|
||||||
|
|||||||
@@ -8,10 +8,14 @@
|
|||||||
/// It also supports unwrapping concrete variants of other enums
|
/// It also supports unwrapping concrete variants of other enums
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// use crate::representations::Literal;
|
/// use crate::Literal;
|
||||||
///
|
///
|
||||||
/// crate::unwrap_or!(Literal::Usize(2) => Literal::Number; return)
|
/// crate::unwrap_or!(Literal::Usize(2) => Literal::Number; return)
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Note: this macro influences the control flow of the surrounding code
|
||||||
|
/// without an `if`, which can be misleading. It should only be used for small,
|
||||||
|
/// straightforward jumps.
|
||||||
macro_rules! unwrap_or {
|
macro_rules! unwrap_or {
|
||||||
($m:expr; $fail:expr) => {{
|
($m:expr; $fail:expr) => {{
|
||||||
if let Some(res) = ($m) { res } else { $fail }
|
if let Some(res) = ($m) { res } else { $fail }
|
||||||
|
|||||||
Reference in New Issue
Block a user