Converted Interner to work with Rc-s

- Interner no longer contains unsafe code
- Tokens now hold a reference to the value they represent directly

This will enable many future improvements
This commit is contained in:
2023-08-19 14:03:05 +01:00
parent ab0b57b1b8
commit 0b887ced70
62 changed files with 592 additions and 762 deletions

View File

@@ -8,7 +8,6 @@ use std::process;
use clap::Parser;
use itertools::Itertools;
use orchidlang::facade::{Environment, PreMacro};
use orchidlang::interner::InternedDisplay;
use orchidlang::systems::stl::StlConfig;
use orchidlang::systems::{io_system, AsynchConfig, IOStream};
use orchidlang::{ast, interpreted, interpreter, Interner, Sym, VName};
@@ -70,36 +69,34 @@ pub fn to_vname(data: &str, i: &Interner) -> VName {
data.split("::").map(|s| i.i(s)).collect::<Vec<_>>()
}
fn print_for_debug(e: &ast::Expr<Sym>, i: &Interner) {
fn print_for_debug(e: &ast::Expr<Sym>) {
print!(
"code: {}\nglossary: {}",
e.bundle(i),
e,
(e.value.collect_names().into_iter())
.map(|t| i.extern_vec(t).join("::"))
.map(|t| t.iter().join("::"))
.join(", ")
)
}
/// A little utility to step through the resolution of a macro set
pub fn macro_debug(premacro: PreMacro, sym: Sym, i: &Interner) {
pub fn macro_debug(premacro: PreMacro, sym: Sym) {
let (mut code, location) = (premacro.consts.get(&sym))
.unwrap_or_else(|| {
panic!(
"Symbol {} not found\nvalid symbols: \n\t{}\n",
i.extern_vec(sym).join("::"),
(premacro.consts.keys())
.map(|t| i.extern_vec(*t).join("::"))
.join("\n\t")
sym.iter().join("::"),
(premacro.consts.keys()).map(|t| t.iter().join("::")).join("\n\t")
)
})
.clone();
println!(
"Debugging macros in {} defined at {}.
Initial state: ",
i.extern_vec(sym).join("::"),
sym.iter().join("::"),
location
);
print_for_debug(&code, i);
print_for_debug(&code);
let mut steps = premacro.step(sym).enumerate();
loop {
let (cmd, _) = cmd_prompt("\ncmd> ").unwrap();
@@ -108,12 +105,12 @@ pub fn macro_debug(premacro: PreMacro, sym: Sym, i: &Interner) {
if let Some((idx, c)) = steps.next() {
code = c;
print!("Step {idx}: ");
print_for_debug(&code, i);
print_for_debug(&code);
} else {
print!("Halted")
},
"p" | "print" => print_for_debug(&code, i),
"d" | "dump" => print!("Rules: {}", premacro.repo.bundle(i)),
"p" | "print" => print_for_debug(&code),
"d" | "dump" => print!("Rules: {}", premacro.repo),
"q" | "quit" => return,
"h" | "help" => print!(
"Available commands:
@@ -146,22 +143,22 @@ pub fn main() {
.add_system(StlConfig { impure: true })
.add_system(asynch)
.add_system(io);
let premacro = i.unwrap(env.load_dir(&dir, &main));
let premacro = env.load_dir(&dir, &main).unwrap();
if args.dump_repo {
println!("Parsed rules: {}", premacro.repo.bundle(&i));
println!("Parsed rules: {}", premacro.repo);
return;
}
if !args.macro_debug.is_empty() {
let sym = i.i(&to_vname(&args.macro_debug, &i));
return macro_debug(premacro, sym, &i);
return macro_debug(premacro, sym);
}
let mut proc = i.unwrap(premacro.build_process(Some(args.macro_limit)));
let mut proc = premacro.build_process(Some(args.macro_limit)).unwrap();
let main = interpreted::Clause::Constant(i.i(&main)).wrap();
let ret = i.unwrap(proc.run(main, None));
let ret = proc.run(main, None).unwrap();
let interpreter::Return { gas, state, inert } = ret;
drop(proc);
if inert {
println!("Settled at {}", state.expr().clause.bundle(&i));
println!("Settled at {}", state.expr().clause);
if let Some(g) = gas {
println!("Remaining gas: {g}")
}

View File

@@ -1,8 +1,10 @@
use std::rc::Rc;
use itertools::Itertools;
use super::ProjectError;
use crate::representations::location::Location;
use crate::{Interner, VName};
use crate::VName;
/// Error produced for the statement `import *`
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -16,11 +18,11 @@ impl ProjectError for ImportAll {
fn description(&self) -> &str {
"a top-level glob import was used"
}
fn message(&self, i: &Interner) -> String {
format!("{} imports *", i.extern_all(&self.offender_mod).join("::"))
fn message(&self) -> String {
format!("{} imports *", self.offender_mod.iter().join("::"))
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
Location::File(self.offender_file.clone())
}
}

View File

@@ -3,7 +3,6 @@ use super::{ErrorPosition, ProjectError};
use crate::parse_layer;
use crate::utils::iter::box_empty;
use crate::utils::BoxedIter;
use crate::Interner;
/// Error produced when [parse_layer] is called without targets. This function
/// produces an error instead of returning a straightforward empty tree because
@@ -17,7 +16,7 @@ impl ProjectError for NoTargets {
"No targets were specified for layer parsing"
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
box_empty()
}
}

View File

@@ -21,21 +21,23 @@ impl ProjectError for NotExported {
fn description(&self) -> &str {
"An import refers to a symbol that exists but isn't exported"
}
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
[
ErrorPosition {
location: Location::File(Rc::new(i.extern_all(&self.file))),
location: Location::File(Rc::new(Interner::extern_all(&self.file))),
message: Some(format!(
"{} isn't exported",
i.extern_all(&self.subpath).join("::")
Interner::extern_all(&self.subpath).join("::")
)),
},
ErrorPosition {
location: Location::File(Rc::new(i.extern_all(&self.referrer_file))),
location: Location::File(Rc::new(Interner::extern_all(
&self.referrer_file,
))),
message: Some(format!(
"{} cannot see this symbol",
i.extern_all(&self.referrer_subpath).join("::")
Interner::extern_all(&self.referrer_subpath).join("::")
)),
},
]

View File

@@ -37,7 +37,7 @@ impl NotFound {
) -> Self {
let last_mod =
orig.walk_ref(&path[..e.pos], false).expect("error occured on next step");
let mut whole_path = prefix.iter().chain(path.iter()).copied();
let mut whole_path = prefix.iter().chain(path.iter()).cloned();
if let Some(file) = &last_mod.extra.file {
Self {
source: Some(source.to_vec()),
@@ -57,14 +57,14 @@ impl ProjectError for NotFound {
fn description(&self) -> &str {
"an import refers to a nonexistent module"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"module {} in {} was not found",
i.extern_all(&self.subpath).join("::"),
i.extern_all(&self.file).join("/"),
Interner::extern_all(&self.subpath).join("::"),
Interner::extern_all(&self.file).join("/"),
)
}
fn one_position(&self, i: &Interner) -> crate::Location {
Location::File(Rc::new(i.extern_all(&self.file)))
fn one_position(&self) -> crate::Location {
Location::File(Rc::new(Interner::extern_all(&self.file)))
}
}

View File

@@ -3,10 +3,8 @@ use std::rc::Rc;
use itertools::Itertools;
use super::{ErrorPosition, ProjectError};
use crate::interner::InternedDisplay;
use crate::parse::Entry;
use crate::utils::BoxedIter;
use crate::Interner;
/// Produced by stages that parse text when it fails.
pub struct ParseErrorWithTokens {
@@ -21,14 +19,14 @@ impl ProjectError for ParseErrorWithTokens {
fn description(&self) -> &str {
self.error.description()
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"Failed to parse code: {}\nTokenized source for context:\n{}",
self.error.message(i),
self.tokens.iter().map(|t| t.to_string_i(i)).join(" "),
self.error.message(),
self.tokens.iter().map(|t| t.to_string()).join(" "),
)
}
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
self.error.positions(i)
fn positions(&self) -> BoxedIter<ErrorPosition> {
self.error.positions()
}
}

View File

@@ -1,10 +1,10 @@
use std::fmt::Debug;
use std::fmt::Display;
use std::rc::Rc;
use crate::interner::InternedDisplay;
use crate::representations::location::Location;
use crate::utils::iter::box_once;
use crate::utils::BoxedIter;
use crate::Interner;
/// A point of interest in resolving the error, such as the point where
/// processing got stuck, a command that is likely to be incorrect
@@ -21,17 +21,17 @@ pub trait ProjectError {
/// A general description of this type of error
fn description(&self) -> &str;
/// A formatted message that includes specific parameters
fn message(&self, _i: &Interner) -> String {
fn message(&self) -> String {
self.description().to_string()
}
/// Code positions relevant to this error. If you don't implement this, you
/// must implement [ProjectError::one_position]
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
box_once(ErrorPosition { location: self.one_position(i), message: None })
fn positions(&self) -> BoxedIter<ErrorPosition> {
box_once(ErrorPosition { location: self.one_position(), 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 {
fn one_position(&self) -> Location {
unimplemented!()
}
/// Convert the error into an `Rc<dyn ProjectError>` to be able to
@@ -44,15 +44,11 @@ pub trait ProjectError {
}
}
impl InternedDisplay for dyn ProjectError {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for dyn ProjectError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let description = self.description();
let message = self.message(i);
let positions = self.positions(i);
let message = self.message();
let positions = self.positions();
writeln!(f, "Project error: {description}\n{message}")?;
for ErrorPosition { location, message } in positions {
writeln!(
@@ -65,6 +61,12 @@ impl InternedDisplay for dyn ProjectError {
}
}
impl Debug for dyn ProjectError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}
/// Alias for a result with an error of [Rc] of [ProjectError] trait object.
/// This is the type of result most commonly returned by pre-run operations.
pub type ProjectResult<T> = Result<T, Rc<dyn ProjectError>>;

View File

@@ -20,15 +20,15 @@ impl ProjectError for TooManySupers {
"an import path starts with more `super` segments than the current \
module's absolute path"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"path {} in {} contains too many `super` steps.",
i.extern_all(&self.path).join("::"),
i.extern_all(&self.offender_mod).join("::")
Interner::extern_all(&self.path).join("::"),
Interner::extern_all(&self.offender_mod).join("::")
)
}
fn one_position(&self, i: &Interner) -> Location {
Location::File(Rc::new(i.extern_all(&self.offender_file)))
fn one_position(&self) -> Location {
Location::File(Rc::new(Interner::extern_all(&self.offender_file)))
}
}

View File

@@ -15,14 +15,14 @@ impl ProjectError for UnexpectedDirectory {
"A stage that deals specifically with code encountered a path that refers \
to a directory"
}
fn one_position(&self, i: &Interner) -> crate::Location {
Location::File(Rc::new(i.extern_all(&self.path)))
fn one_position(&self) -> crate::Location {
Location::File(Rc::new(Interner::extern_all(&self.path)))
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"{} was expected to be a file but a directory was found",
i.extern_all(&self.path).join("/")
Interner::extern_all(&self.path).join("/")
)
}
}

View File

@@ -16,13 +16,13 @@ impl ProjectError for VisibilityMismatch {
fn description(&self) -> &str {
"Some occurences of a namespace are exported but others are not"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"{} is opened multiple times with different visibilities",
i.extern_all(&self.namespace).join("::")
Interner::extern_all(&self.namespace).join("::")
)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
Location::File(self.file.clone())
}
}

View File

@@ -65,7 +65,7 @@ impl<'a> Environment<'a> {
) -> ProjectResult<PreMacro<'a>> {
let i = self.i;
let CompiledEnv { prelude, systems, tree } = self.compile()?;
let file_cache = file_loader::mk_dir_cache(dir.to_path_buf(), i);
let file_cache = file_loader::mk_dir_cache(dir.to_path_buf());
let vname_tree = parse_layer(
iter::once(target),
&|path| file_cache.find(path),

View File

@@ -42,11 +42,12 @@ impl<'a> PreMacro<'a> {
repo,
consts: (consts.into_iter())
.map(|(name, expr)| {
let location = (i.r(name).split_last())
let location = (name.split_last())
.and_then(|(_, path)| {
let origin = (tree.0.walk_ref(path, false))
.expect("path sourced from symbol names");
origin.extra.file.as_ref().map(|path| i.extern_all(&path[..]))
(origin.extra.file.as_ref())
.map(|path| Interner::extern_all(&path[..]))
})
.map(|p| Location::File(Rc::new(p)))
.unwrap_or(Location::Unknown);
@@ -73,7 +74,7 @@ impl<'a> PreMacro<'a> {
return Err(
MacroTimeout {
location: source_location.clone(),
symbol: *name,
symbol: name.clone(),
limit,
}
.rc(),
@@ -85,7 +86,7 @@ impl<'a> PreMacro<'a> {
repo.pass(source).unwrap_or_else(|| source.clone())
};
let runtree = ast_to_interpreted(&unmatched).map_err(|e| e.rc())?;
symbols.insert(*name, runtree);
symbols.insert(name.clone(), runtree);
}
Ok(Process {
symbols,
@@ -118,15 +119,15 @@ impl ProjectError for MacroTimeout {
"Macro execution has not halted"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"Macro execution during the processing of {} took more than {} steps",
i.extern_vec(self.symbol).join("::"),
self.symbol.extern_vec().join("::"),
self.limit
)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}

View File

@@ -38,9 +38,9 @@ impl<'a> Process<'a> {
let sym = self.symbols.get(&key).expect("symbol must exist");
sym.search_all(&mut |s: &ExprInst| {
let expr = s.expr();
if let interpreted::Clause::Constant(sym) = expr.clause {
if !self.symbols.contains_key(&sym) {
errors.push((sym, expr.location.clone()))
if let interpreted::Clause::Constant(sym) = &expr.clause {
if !self.symbols.contains_key(sym) {
errors.push((sym.clone(), expr.location.clone()))
}
}
None::<()>
@@ -53,8 +53,10 @@ impl<'a> Process<'a> {
/// produced
pub fn validate_refs(&self) -> ProjectResult<()> {
for key in self.symbols.keys() {
if let Some((symbol, location)) = self.unbound_refs(*key).pop() {
return Err(MissingSymbol { location, referrer: *key, symbol }.rc());
if let Some((symbol, location)) = self.unbound_refs(key.clone()).pop() {
return Err(
MissingSymbol { location, referrer: key.clone(), symbol }.rc(),
);
}
}
Ok(())
@@ -74,15 +76,15 @@ impl ProjectError for MissingSymbol {
that macro execution didn't correctly halt."
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"The symbol {} referenced in {} does not exist",
i.extern_vec(self.symbol).join("::"),
i.extern_vec(self.referrer).join("::")
self.symbol.extern_vec().join("::"),
self.referrer.extern_vec().join("::")
)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}

View File

@@ -52,14 +52,14 @@ impl ProjectError for MissingSystemCode {
fn description(&self) -> &str {
"A system tried to import a path that doesn't exist"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"Path {} is not defined by {} or any system before it",
i.extern_all(&self.path).join("::"),
Interner::extern_all(&self.path).join("::"),
self.system.join("::")
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
box_empty()
}
}

View File

@@ -108,7 +108,7 @@ impl<T: CPSPayload> Atomic for CPSBox<T> {
}
/// Like [init_cps] but wrapped in a [ConstTree] for init-time usage
pub fn mk_const<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
pub fn const_cps<T: CPSPayload>(argc: usize, payload: T) -> ConstTree {
ConstTree::xfn(CPSFn::new(argc, payload))
}

View File

@@ -5,9 +5,9 @@
mod monotype;
mod multitype;
mod token;
mod traits;
// mod traits;
pub use monotype::TypedInterner;
pub use multitype::Interner;
pub use token::Tok;
pub use traits::{DisplayBundle, InternedDisplay, InternedInto};
// pub use traits::{DisplayBundle, InternedDisplay, InternedInto};

View File

@@ -1,7 +1,7 @@
use std::borrow::Borrow;
use std::cell::RefCell;
use std::hash::{BuildHasher, Hash};
use std::num::NonZeroU32;
use std::rc::Rc;
use hashbrown::HashMap;
@@ -11,20 +11,19 @@ use super::token::Tok;
/// Lasso but much simpler, in part because not much can be known about the
/// type.
pub struct TypedInterner<T: 'static + Eq + Hash + Clone> {
tokens: RefCell<HashMap<&'static T, Tok<T>>>,
values: RefCell<Vec<(&'static T, bool)>>,
tokens: RefCell<HashMap<Rc<T>, Tok<T>>>,
}
impl<T: Eq + Hash + Clone> TypedInterner<T> {
/// Create a fresh interner instance
pub fn new() -> Self {
Self {
tokens: RefCell::new(HashMap::new()),
values: RefCell::new(Vec::new()),
}
pub fn new() -> Rc<Self> {
Rc::new(Self { tokens: RefCell::new(HashMap::new()) })
}
/// Intern an object, returning a token
pub fn i<Q: ?Sized + Eq + Hash + ToOwned<Owned = T>>(&self, q: &Q) -> Tok<T>
pub fn i<Q: ?Sized + Eq + Hash + ToOwned<Owned = T>>(
self: &Rc<Self>,
q: &Q,
) -> Tok<T>
where
T: Borrow<Q>,
{
@@ -34,65 +33,11 @@ impl<T: Eq + Hash + Clone> TypedInterner<T> {
.raw_entry_mut()
.from_hash(hash, |k| <T as Borrow<Q>>::borrow(k) == q);
let kv = raw_entry.or_insert_with(|| {
let mut values = self.values.borrow_mut();
let uniq_key: NonZeroU32 =
(values.len() as u32 + 1u32).try_into().expect("can never be zero");
let keybox = Box::new(q.to_owned());
let keyref = Box::leak(keybox);
values.push((keyref, true));
let token = Tok::<T>::from_id(uniq_key);
(keyref, token)
let keyrc = Rc::new(q.to_owned());
let token = Tok::<T>::new(keyrc.clone(), Rc::downgrade(self));
(keyrc, token)
});
*kv.1
}
/// Resolve a token, obtaining a reference to the held object.
/// It is illegal to use a token obtained from one interner with
/// another.
pub fn r(&self, t: Tok<T>) -> &T {
let values = self.values.borrow();
let key = t.into_usize() - 1;
values[key].0.borrow()
}
/// Intern a static reference without allocating the data on the heap
#[allow(unused)]
pub fn intern_static(&self, tref: &'static T) -> Tok<T> {
let mut tokens = self.tokens.borrow_mut();
let token = *tokens
.raw_entry_mut()
.from_key(tref)
.or_insert_with(|| {
let mut values = self.values.borrow_mut();
let uniq_key: NonZeroU32 =
(values.len() as u32 + 1u32).try_into().expect("can never be zero");
values.push((tref, false));
let token = Tok::<T>::from_id(uniq_key);
(tref, token)
})
.1;
token
}
}
impl<T: Eq + Hash + Clone> Default for TypedInterner<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Eq + Hash + Clone> Drop for TypedInterner<T> {
fn drop(&mut self) {
// make sure all values leaked by us are dropped
// FIXME: with the new hashmap logic we can actually store Rc-s
// which negates the need for unsafe here
let mut values = self.values.borrow_mut();
for (item, owned) in values.drain(..) {
if !owned {
continue;
}
let _ = unsafe { Box::from_raw((item as *const T).cast_mut()) };
}
kv.1.clone()
}
}

View File

@@ -8,7 +8,7 @@ use hashbrown::HashMap;
use super::monotype::TypedInterner;
use super::token::Tok;
use super::InternedDisplay;
// use super::InternedDisplay;
/// A collection of interners based on their type. Allows to intern any object
/// that implements [ToOwned]. Objects of the same type are stored together in a
@@ -32,57 +32,33 @@ impl Interner {
interner.i(q)
}
/// Resolve a token to a reference
pub fn r<T: 'static + Eq + Hash + Clone>(&self, t: Tok<T>) -> &T {
let mut interners = self.interners.borrow_mut();
let interner = get_interner(&mut interners);
// TODO: figure this out
unsafe { (interner.r(t) as *const T).as_ref().unwrap() }
}
/// Fully resolve an interned list of interned things
/// TODO: make this generic over containers
pub fn extern_vec<T: 'static + Eq + Hash + Clone>(
&self,
t: Tok<Vec<Tok<T>>>,
) -> Vec<T> {
let mut interners = self.interners.borrow_mut();
let v_int = get_interner(&mut interners);
let t_int = get_interner(&mut interners);
let v = v_int.r(t);
v.iter().map(|t| t_int.r(*t)).cloned().collect()
}
/// Fully resolve a list of interned things.
pub fn extern_all<T: 'static + Eq + Hash + Clone>(
&self,
s: &[Tok<T>],
) -> Vec<T> {
s.iter().map(|t| self.r(*t)).cloned().collect()
pub fn extern_all<T: 'static + Eq + Hash + Clone>(s: &[Tok<T>]) -> Vec<T> {
s.iter().map(|t| (**t).clone()).collect()
}
/// A variant of `unwrap` using [InternedDisplay] to circumvent `unwrap`'s
/// dependencyon [Debug]. For clarity, [expect] should be preferred.
pub fn unwrap<T, E: InternedDisplay>(&self, result: Result<T, E>) -> T {
result.unwrap_or_else(|e| {
println!("Unwrapped Error: {}", e.bundle(self));
panic!("Unwrapped an error");
})
}
// /// A variant of `unwrap` using [InternedDisplay] to circumvent `unwrap`'s
// /// dependencyon [Debug]. For clarity, [expect] should be preferred.
// pub fn unwrap<T, E: InternedDisplay>(&self, result: Result<T, E>) -> T {
// result.unwrap_or_else(|e| {
// println!("Unwrapped Error: {}", e.bundle(self));
// panic!("Unwrapped an error");
// })
// }
/// A variant of `expect` using [InternedDisplay] to circumvent `expect`'s
/// depeendency on [Debug].
pub fn expect<T, E: InternedDisplay>(
&self,
result: Result<T, E>,
msg: &str,
) -> T {
result.unwrap_or_else(|e| {
println!("Expectation failed: {msg}");
println!("Error: {}", e.bundle(self));
panic!("Expected an error");
})
}
// /// A variant of `expect` using [InternedDisplay] to circumvent `expect`'s
// /// depeendency on [Debug].
// pub fn expect<T, E: InternedDisplay>(
// &self,
// result: Result<T, E>,
// msg: &str,
// ) -> T {
// result.unwrap_or_else(|e| {
// println!("Expectation failed: {msg}");
// println!("Error: {}", e.bundle(self));
// panic!("Expected an error");
// })
// }
}
impl Default for Interner {
@@ -98,7 +74,7 @@ fn get_interner<T: 'static + Eq + Hash + Clone>(
let boxed = interners
.raw_entry_mut()
.from_key(&TypeId::of::<T>())
.or_insert_with(|| (TypeId::of::<T>(), Rc::new(TypedInterner::<T>::new())))
.or_insert_with(|| (TypeId::of::<T>(), TypedInterner::<T>::new()))
.1
.clone();
boxed.downcast().expect("the typeid is supposed to protect from this")

View File

@@ -1,66 +1,94 @@
use std::cmp::PartialEq;
use std::fmt::Debug;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::num::NonZeroUsize;
use std::ops::Deref;
use std::rc::{Rc, Weak};
use super::TypedInterner;
/// A number representing an object of type `T` stored in some interner. It is a
/// logic error to compare tokens obtained from different interners, or to use a
/// token with an interner other than the one that created it, but this is
/// currently not enforced.
pub struct Tok<T> {
id: NonZeroU32,
phantom_data: PhantomData<T>,
#[derive(Clone)]
pub struct Tok<T: Eq + Hash + Clone + 'static> {
data: Rc<T>,
interner: Weak<TypedInterner<T>>,
}
impl<T> Tok<T> {
/// Wrap an ID number into a token
pub fn from_id(id: NonZeroU32) -> Self {
Self { id, phantom_data: PhantomData }
impl<T: Eq + Hash + Clone + 'static> Tok<T> {
/// Create a new token. Used exclusively by the interner
pub(crate) fn new(data: Rc<T>, interner: Weak<TypedInterner<T>>) -> Self {
Self { data, interner }
}
/// Take the ID number out of a token
pub fn into_id(self) -> NonZeroU32 {
self.id
pub fn id(&self) -> NonZeroUsize {
((self.data.as_ref() as *const T as usize).try_into())
.expect("Pointer can always be cast to nonzero")
}
/// Cast into usize
pub fn into_usize(self) -> usize {
let zero: u32 = self.id.into();
zero as usize
pub fn usize(&self) -> usize {
self.id().into()
}
///
pub fn assert_comparable(&self, other: &Self) {
let iref = self.interner.as_ptr() as usize;
assert!(
iref == other.interner.as_ptr() as usize,
"Tokens must come from the same interner"
);
}
}
impl<T> Debug for Tok<T> {
impl<T: Eq + Hash + Clone + 'static> Tok<Vec<Tok<T>>> {
/// Extern all elements of the vector in a new vector
pub fn extern_vec(&self) -> Vec<T> {
self.iter().map(|t| (**t).clone()).collect()
}
}
impl<T: Eq + Hash + Clone + 'static> Deref for Tok<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.data.as_ref()
}
}
impl<T: Eq + Hash + Clone + 'static> Debug for Tok<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Token({})", self.id)
write!(f, "Token({})", self.id())
}
}
impl<T> Copy for Tok<T> {}
impl<T> Clone for Tok<T> {
fn clone(&self) -> Self {
Self { id: self.id, phantom_data: PhantomData }
impl<T: Eq + Hash + Clone + Display + 'static> Display for Tok<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", *self)
}
}
impl<T> Eq for Tok<T> {}
impl<T> PartialEq for Tok<T> {
impl<T: Eq + Hash + Clone + 'static> Eq for Tok<T> {}
impl<T: Eq + Hash + Clone + 'static> PartialEq for Tok<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
self.assert_comparable(other);
self.id() == other.id()
}
}
impl<T> Ord for Tok<T> {
impl<T: Eq + Hash + Clone + 'static> Ord for Tok<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.id.cmp(&other.id)
self.assert_comparable(other);
self.id().cmp(&other.id())
}
}
impl<T> PartialOrd for Tok<T> {
impl<T: Eq + Hash + Clone + 'static> PartialOrd for Tok<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> Hash for Tok<T> {
impl<T: Eq + Hash + Clone + 'static> Hash for Tok<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_u32(self.id.into())
state.write_usize(self.usize())
}
}

View File

@@ -108,7 +108,7 @@ pub fn apply(
if let Some(sym) = ctx.symbols.get(name) {
Ok((Clause::Apply { f: sym.clone(), x }, (ctx.gas, false)))
} else {
Err(RuntimeError::MissingSymbol(*name, loc.clone()))
Err(RuntimeError::MissingSymbol(name.clone(), loc.clone()))
},
Clause::P(Primitive::Atom(atom)) => {
// take a step in expanding atom

View File

@@ -1,7 +1,7 @@
use std::fmt::Display;
use std::rc::Rc;
use crate::foreign::ExternError;
use crate::interner::InternedDisplay;
use crate::representations::interpreted::ExprInst;
use crate::{Location, Sym};
@@ -22,12 +22,8 @@ impl From<Rc<dyn ExternError>> for RuntimeError {
}
}
impl InternedDisplay for RuntimeError {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &crate::Interner,
) -> std::fmt::Result {
impl Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Extern(e) => write!(f, "Error in external function: {e}"),
Self::NonFunctionApplication(expr) => {
@@ -37,7 +33,7 @@ impl InternedDisplay for RuntimeError {
write!(
f,
"{}, called at {loc} is not loaded",
i.extern_vec(*sym).join("::")
sym.extern_vec().join("::")
)
},
}

View File

@@ -30,8 +30,9 @@ pub fn run(expr: ExprInst, mut ctx: Context) -> Result<Return, RuntimeError> {
i = clause.clone();
},
Clause::Constant(c) => {
let symval = (ctx.symbols.get(c))
.ok_or_else(|| RuntimeError::MissingSymbol(*c, loc.clone()))?;
let symval = (ctx.symbols.get(c)).ok_or_else(|| {
RuntimeError::MissingSymbol(c.clone(), loc.clone())
})?;
ctx.gas = ctx.gas.map(|g| g - 1); // cost of lookup
i = symval.expr().clause.clone();
},

View File

@@ -5,9 +5,8 @@ use itertools::Itertools;
use super::{Entry, Lexeme};
use crate::error::{ErrorPosition, ProjectError};
use crate::interner::InternedDisplay;
use crate::utils::BoxedIter;
use crate::{Interner, Location, Tok};
use crate::{Location, Tok};
#[derive(Debug)]
pub struct LineNeedsPrefix {
@@ -17,10 +16,10 @@ impl ProjectError for LineNeedsPrefix {
fn description(&self) -> &str {
"This linetype requires a prefix"
}
fn message(&self, i: &Interner) -> String {
format!("{} cannot appear at the beginning of a line", self.entry.bundle(i))
fn message(&self) -> String {
format!("{} cannot appear at the beginning of a line", self.entry)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.entry.location()
}
}
@@ -35,13 +34,13 @@ impl ProjectError for UnexpectedEOL {
"The line ended abruptly"
}
fn message(&self, _i: &Interner) -> String {
fn message(&self) -> String {
"The line ends unexpectedly here. In Orchid, all line breaks outside \
parentheses start a new declaration"
.to_string()
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.entry.location()
}
}
@@ -53,7 +52,7 @@ impl ProjectError for ExpectedEOL {
fn description(&self) -> &str {
"Expected the end of the line"
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}
@@ -64,8 +63,8 @@ pub struct ExpectedName {
}
impl ExpectedName {
pub fn expect(entry: &Entry) -> Result<Tok<String>, Rc<dyn ProjectError>> {
match entry.lexeme {
Lexeme::Name(n) => Ok(n),
match &entry.lexeme {
Lexeme::Name(n) => Ok(n.clone()),
_ => Err(Self { entry: entry.clone() }.rc()),
}
}
@@ -75,18 +74,18 @@ impl ProjectError for ExpectedName {
"A name was expected here, but something else was found"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
if self.entry.is_keyword() {
format!(
"{} is a restricted keyword and cannot be used as a name",
self.entry.bundle(i)
self.entry
)
} else {
format!("Expected a name, found {}", self.entry.bundle(i))
format!("Expected a name, found {}", self.entry)
}
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.entry.location()
}
}
@@ -111,22 +110,19 @@ impl ProjectError for Expected {
fn description(&self) -> &str {
"A concrete token was expected but something else was found"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
let list = match &self.expected[..] {
&[] => return "Unsatisfiable expectation".to_string(),
[only] => only.to_string_i(i),
[a, b] => format!("either {} or {}", a.bundle(i), b.bundle(i)),
[variants @ .., last] => format!(
"any of {} or {}",
variants.iter().map(|l| l.to_string_i(i)).join(", "),
last.bundle(i)
),
[only] => only.to_string(),
[a, b] => format!("either {a} or {b}"),
[variants @ .., last] =>
format!("any of {} or {last}", variants.iter().join(", ")),
};
let or_name = if self.or_name { " or a name" } else { "" };
format!("Expected {}{} but found {}", list, or_name, self.found.bundle(i))
format!("Expected {list}{or_name} but found {}", self.found)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.found.location()
}
}
@@ -139,11 +135,11 @@ impl ProjectError for ReservedToken {
"A token reserved for future use was found in the code"
}
fn message(&self, i: &Interner) -> String {
format!("{} is a reserved token", self.entry.bundle(i))
fn message(&self) -> String {
format!("{} is a reserved token", self.entry)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.entry.location()
}
}
@@ -157,11 +153,11 @@ impl ProjectError for BadTokenInRegion {
"A token was found in a region where it should not appear"
}
fn message(&self, i: &Interner) -> String {
format!("{} cannot appear in {}", self.entry.bundle(i), self.region)
fn message(&self) -> String {
format!("{} cannot appear in {}", self.entry, self.region)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.entry.location()
}
}
@@ -175,11 +171,11 @@ impl ProjectError for NotFound {
"A specific lexeme was expected but not found in the given range"
}
fn message(&self, _i: &Interner) -> String {
fn message(&self) -> String {
format!("{} was expected", self.expected)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}
@@ -191,7 +187,7 @@ impl ProjectError for LeadingNS {
fn description(&self) -> &str {
":: can only follow a name token"
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}
@@ -203,10 +199,10 @@ impl ProjectError for MisalignedParen {
fn description(&self) -> &str {
"Parentheses (), [] and {} must always pair up"
}
fn message(&self, i: &Interner) -> String {
format!("This {} has no pair", self.entry.bundle(i))
fn message(&self) -> String {
format!("This {} has no pair", self.entry)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.entry.location()
}
}
@@ -218,7 +214,7 @@ impl ProjectError for NamespacedExport {
fn description(&self) -> &str {
"Exports can only refer to unnamespaced names in the local namespace"
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}
@@ -230,7 +226,7 @@ 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 {
fn one_position(&self) -> Location {
self.location.clone()
}
}
@@ -244,7 +240,7 @@ impl ProjectError for LexError {
fn description(&self) -> &str {
"An error occured during tokenization"
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
let file = self.file.clone();
Box::new(self.errors.iter().map(move |s| ErrorPosition {
location: Location::Range {

View File

@@ -1,10 +1,11 @@
use std::fmt;
use std::fmt::{self, Display};
use std::ops::Range;
use std::rc::Rc;
use chumsky::prelude::*;
use chumsky::text::keyword;
use chumsky::Parser;
use itertools::Itertools;
use ordered_float::NotNan;
use super::context::Context;
@@ -12,7 +13,7 @@ use super::decls::SimpleParser;
use super::number::print_nat16;
use super::{comment, name, number, placeholder, string};
use crate::ast::{PHClass, Placeholder};
use crate::interner::{InternedDisplay, Interner, Tok};
use crate::interner::Tok;
use crate::representations::Literal;
use crate::Location;
@@ -51,13 +52,9 @@ impl Entry {
}
}
impl InternedDisplay for Entry {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
self.lexeme.fmt_i(f, i)
impl Display for Entry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.lexeme.fmt(f)
}
}
@@ -120,15 +117,11 @@ pub enum Lexeme {
Placeh(Placeholder),
}
impl InternedDisplay for Lexeme {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for Lexeme {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Literal(l) => write!(f, "{:?}", l),
Self::Name(token) => write!(f, "{}", i.r(*token)),
Self::Name(token) => write!(f, "{}", **token),
Self::Walrus => write!(f, ":="),
Self::Arrow(prio) => write!(f, "={}=>", print_nat16(*prio)),
Self::NS => write!(f, "::"),
@@ -151,10 +144,10 @@ impl InternedDisplay for Lexeme {
Self::Const => write!(f, "const"),
Self::Macro => write!(f, "macro"),
Self::Placeh(Placeholder { name, class }) => match *class {
PHClass::Scalar => write!(f, "${}", i.r(*name)),
PHClass::Scalar => write!(f, "${}", **name),
PHClass::Vec { nonzero, prio } => {
if nonzero { write!(f, "...") } else { write!(f, "..") }?;
write!(f, "${}", i.r(*name))?;
write!(f, "${}", **name)?;
if prio != 0 {
write!(f, ":{}", prio)?;
};
@@ -182,13 +175,9 @@ impl Lexeme {
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct LexedText(pub Vec<Entry>);
impl InternedDisplay for LexedText {
fn fmt_i(&self, f: &mut fmt::Formatter<'_>, i: &Interner) -> fmt::Result {
for tok in self.0.iter() {
tok.fmt_i(f, i)?;
f.write_str(" ")?
}
Ok(())
impl Display for LexedText {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.iter().join(" "))
}
}

View File

@@ -43,8 +43,8 @@ fn parse_multiname_branch(
let comma = ctx.interner().i(",");
let (subnames, cursor) = parse_multiname_rec(cursor, ctx.clone())?;
let (delim, cursor) = cursor.trim().pop()?;
match delim.lexeme {
Lexeme::Name(n) if n == comma => {
match &delim.lexeme {
Lexeme::Name(n) if n == &comma => {
let (tail, cont) = parse_multiname_branch(cursor, ctx)?;
Ok((box_chain!(subnames, tail), cont))
},
@@ -74,7 +74,7 @@ fn parse_multiname_rec(
loop {
let head;
(head, cursor) = cursor.trim().pop()?;
match head.lexeme {
match &head.lexeme {
Lexeme::Name(n) => names.push(n),
Lexeme::RP('[') => break,
_ => {
@@ -87,7 +87,10 @@ fn parse_multiname_rec(
},
}
}
Ok((Box::new(names.into_iter().map(Subresult::new_named)), cursor))
Ok((
Box::new(names.into_iter().map(|n| Subresult::new_named(n.clone()))),
cursor,
))
},
Lexeme::Name(n) if *n == star =>
Ok((box_once(Subresult::new_glob()), cursor)),
@@ -96,10 +99,10 @@ fn parse_multiname_rec(
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(|sr| sr.push_front(*n)));
let out = Box::new(out.map(|sr| sr.push_front(n.clone())));
Ok((out, cursor))
} else {
Ok((box_once(Subresult::new_named(*n)), cursor))
Ok((box_once(Subresult::new_named(n.clone())), cursor))
}
},
_ => Err(

View File

@@ -201,14 +201,14 @@ fn parse_exprv(
},
Lexeme::Placeh(ph) => {
output.push(Expr {
value: Clause::Placeh(*ph),
value: Clause::Placeh(ph.clone()),
location: current.location(),
});
cursor = cursor.step()?;
},
Lexeme::Name(n) => {
let location = cursor.location();
let mut fullname = vec![*n];
let mut fullname = vec![n.clone()];
while cursor.get(1).ok().map(|e| &e.lexeme) == Some(&Lexeme::NS) {
fullname.push(ExpectedName::expect(cursor.get(2)?)?);
cursor = cursor.step()?.step()?;

View File

@@ -24,10 +24,10 @@ impl ProjectError for FileLoadingError {
fn description(&self) -> &str {
"Neither a file nor a directory could be read from the requested path"
}
fn one_position(&self, _i: &Interner) -> crate::Location {
fn one_position(&self) -> crate::Location {
Location::File(Rc::new(self.path.clone()))
}
fn message(&self, _i: &Interner) -> String {
fn message(&self) -> String {
format!("File: {}\nDirectory: {}", self.file, self.dir)
}
}
@@ -89,9 +89,9 @@ pub fn load_file(root: &Path, path: &[impl AsRef<str>]) -> IOResult {
}
/// Generates a cached file loader for a directory
pub fn mk_dir_cache(root: PathBuf, i: &Interner) -> Cache<VName, IOResult> {
pub fn mk_dir_cache(root: PathBuf) -> Cache<'static, VName, IOResult> {
Cache::new(move |vname: VName, _this| -> IOResult {
let path = vname.iter().map(|t| i.r(*t).as_str()).collect::<Vec<_>>();
let path = vname.iter().map(|t| t.as_str()).collect::<Vec<_>>();
load_file(&root, &path)
})
}
@@ -130,12 +130,11 @@ pub fn load_embed<T: 'static + RustEmbed>(path: &str, ext: &str) -> IOResult {
}
/// Generates a cached file loader for a [RustEmbed]
pub fn mk_embed_cache<'a, T: 'static + RustEmbed>(
ext: &'a str,
i: &'a Interner,
) -> Cache<'a, Vec<Stok>, IOResult> {
pub fn mk_embed_cache<T: 'static + RustEmbed>(
ext: &str,
) -> Cache<'_, Vec<Stok>, IOResult> {
Cache::new(move |vname: VName, _this| -> IOResult {
let path = i.extern_all(&vname).join("/");
let path = Interner::extern_all(&vname).join("/");
load_embed::<T>(&path, ext)
})
}

View File

@@ -12,10 +12,9 @@ pub fn import_abs_path(
// path of module within file
let mod_pathv = mod_stack.iter().rev_vec_clone();
// path of module within compilation
let abs_pathv = src_path
.iter()
.copied()
.chain(mod_pathv.iter().copied())
let abs_pathv = (src_path.iter())
.chain(mod_pathv.iter())
.cloned()
.collect::<Vec<_>>();
// preload-target path relative to module
// preload-target path within compilation

View File

@@ -17,7 +17,7 @@ fn resolve_rec(
Some(alias.clone())
} else if let Some((foot, body)) = namespace.split_last() {
let mut new_beginning = resolve_rec(body, alias_map)?;
new_beginning.push(*foot);
new_beginning.push(foot.clone());
Some(new_beginning)
} else {
None
@@ -61,7 +61,7 @@ fn apply_aliases_rec(
ModMember::Item(expr) =>
ModMember::Item(process_expr(expr, alias_map, injected_as)),
ModMember::Sub(module) => {
let subpath = path.push(*name);
let subpath = path.push(name.clone());
let new_mod = if !updated(&subpath.iter().rev_vec_clone()) {
module.clone()
} else {
@@ -70,7 +70,7 @@ fn apply_aliases_rec(
ModMember::Sub(new_mod)
},
};
(*name, ModEntry { exported: *exported, member })
(name.clone(), ModEntry { exported: *exported, member })
})
.collect::<HashMap<_, _>>();
let rules = (module.extra.rules.iter())
@@ -94,7 +94,7 @@ fn apply_aliases_rec(
rules,
exports: (module.extra.exports.iter())
.map(|(k, v)| {
(*k, resolve(v, alias_map, injected_as).unwrap_or(v.clone()))
(k.clone(), resolve(v, alias_map, injected_as).unwrap_or(v.clone()))
})
.collect(),
file: module.extra.file.clone(),

View File

@@ -105,13 +105,13 @@ fn collect_aliases_rec(
if !updated(&mod_path_v) {
return Ok(());
};
for (&name, target_mod_name) in module.extra.imports_from.iter() {
let target_sym_v = pushed(target_mod_name, name);
for (name, target_mod_name) in module.extra.imports_from.iter() {
let target_sym_v = pushed(target_mod_name, name.clone());
assert_visible(&mod_path_v, &target_sym_v, project)?;
let sym_path_v = pushed(&mod_path_v, name);
let sym_path_v = pushed(&mod_path_v, name.clone());
let target_mod = (project.0.walk_ref(target_mod_name, false))
.expect("checked above in assert_visible");
let target_sym = (target_mod.extra.exports.get(&name))
let target_sym = (target_mod.extra.exports.get(name))
.ok_or_else(|| {
let file_len =
target_mod.extra.file.as_ref().unwrap_or(target_mod_name).len();
@@ -125,10 +125,10 @@ fn collect_aliases_rec(
.clone();
alias_map.link(sym_path_v, target_sym);
}
for (&name, entry) in module.items.iter() {
for (name, entry) in module.items.iter() {
let submodule = unwrap_or!(&entry.member => ModMember::Sub; continue);
collect_aliases_rec(
path.push(name),
path.push(name.clone()),
submodule,
project,
alias_map,

View File

@@ -30,8 +30,8 @@ pub fn parse_layer<'a>(
module.extra.exports.get(item).cloned()
};
let injected_names = |path: Tok<Vec<Tok<String>>>| {
let module = environment.0.walk_ref(&i.r(path)[..], false).ok()?;
Some(Rc::new(module.extra.exports.keys().copied().collect()))
let module = environment.0.walk_ref(&path, false).ok()?;
Some(Rc::new(module.extra.exports.keys().cloned().collect()))
};
let source =
source_loader::load_source(targets, prelude, i, loader, &|path| {

View File

@@ -76,7 +76,8 @@ fn source_to_module(
let imports_from = (imports.iter())
.map(|imp| -> ProjectResult<_> {
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.clone().expect("glob imports had just been resolved"));
let mut abs_path = absolute_path(&path_v, &imp_path_v, i)
.expect("should have failed in preparsing");
let name = abs_path.pop().ok_or_else(|| {
@@ -92,19 +93,19 @@ fn source_to_module(
.collect::<Result<HashMap<_, _>, _>>()?;
let exports = (data.iter())
.flat_map(|ent| {
let mk_ent = |name| (name, pushed(&path_v, name));
let mk_ent = |name: Tok<String>| (name.clone(), pushed(&path_v, name));
match ent {
FileEntry::Export(names) => Box::new(names.iter().copied().map(mk_ent)),
FileEntry::Export(names) => Box::new(names.iter().cloned().map(mk_ent)),
FileEntry::Exported(mem) => match mem {
Member::Constant(constant) => box_once(mk_ent(constant.name)),
Member::Module(ns) => box_once(mk_ent(ns.name)),
Member::Constant(constant) => box_once(mk_ent(constant.name.clone())),
Member::Module(ns) => box_once(mk_ent(ns.name.clone())),
Member::Rule(rule) => {
let mut names = Vec::new();
for e in rule.pattern.iter() {
e.search_all(&mut |e| {
if let Clause::Name(n) = &e.value {
if let Some([name]) = n.strip_prefix(&path_v[..]) {
names.push((*name, n.clone()))
names.push((name.clone(), n.clone()))
}
}
None::<()>
@@ -134,7 +135,7 @@ fn source_to_module(
panic!("Preparsed should include entries for all submodules")
);
let module = match source_to_module(
path.push(ns.name),
path.push(ns.name.clone()),
new_prep,
ns.body,
i,
@@ -144,7 +145,7 @@ fn source_to_module(
Ok(t) => t,
};
let member = ModMember::Sub(module);
Some(Ok((ns.name, ModEntry { exported, member })))
Some(Ok((ns.name.clone(), ModEntry { exported, member })))
},
Member::Constant(Constant { name, value }) => {
let member = ModMember::Item(value);
@@ -184,7 +185,7 @@ fn files_to_module(
let path_v = path.iter().rev_vec_clone();
if files.len() == 1 && files[0].path.len() == lvl {
return source_to_module(
path,
path.clone(),
&files[0].loaded.preparsed.0,
files[0].parsed.clone(),
i,
@@ -192,18 +193,19 @@ fn files_to_module(
);
}
let items = (files.into_iter())
.group_by(|f| f.path[lvl])
.group_by(|f| f.path[lvl].clone())
.into_iter()
.map(|(namespace, files)| -> ProjectResult<_> {
let subpath = path.push(namespace);
let subpath = path.push(namespace.clone());
let files_v = files.collect::<Vec<_>>();
let module = files_to_module(subpath, files_v, i)?;
let member = ModMember::Sub(module);
Ok((namespace, ModEntry { exported: true, member }))
})
.collect::<Result<HashMap<_, _>, _>>()?;
let exports: HashMap<_, _> =
items.keys().copied().map(|name| (name, pushed(&path_v, name))).collect();
let exports: HashMap<_, _> = (items.keys())
.map(|name| (name.clone(), pushed(&path_v, name.clone())))
.collect();
Ok(Module {
items,
imports: vec![],
@@ -223,7 +225,7 @@ pub fn build_tree(
injected: &impl InjectedOperatorsFn,
) -> ProjectResult<ProjectTree<VName>> {
assert!(!files.is_empty(), "A tree requires at least one module");
let ops_cache = collect_ops::mk_cache(&files, i, injected);
let ops_cache = collect_ops::mk_cache(&files, injected);
let mut entries = files
.iter()
.map(|(path, loaded)| {

View File

@@ -4,7 +4,7 @@ use hashbrown::HashSet;
use trait_set::trait_set;
use crate::error::{NotFound, ProjectError, ProjectResult};
use crate::interner::{Interner, Tok};
use crate::interner::Tok;
use crate::pipeline::source_loader::LoadedSourceTable;
use crate::representations::tree::WalkErrorKind;
use crate::utils::{split_max_prefix, Cache};
@@ -28,22 +28,21 @@ fn coprefix<T: Eq>(
pub fn collect_exported_ops(
path: Sym,
loaded: &LoadedSourceTable,
i: &Interner,
injected: &impl InjectedOperatorsFn,
) -> OpsResult {
let injected = injected(path).unwrap_or_else(|| Rc::new(HashSet::new()));
let path_s = &i.r(path)[..];
match split_max_prefix(path_s, &|n| loaded.contains_key(n)) {
let injected =
injected(path.clone()).unwrap_or_else(|| Rc::new(HashSet::new()));
match split_max_prefix(&path, &|n| loaded.contains_key(n)) {
None => {
let ops = (loaded.keys())
.filter_map(|modname| {
if path_s.len() == coprefix(path_s.iter(), modname.iter()) {
Some(modname[path_s.len()])
if path.len() == coprefix(path.iter(), modname.iter()) {
Some(modname[path.len()].clone())
} else {
None
}
})
.chain(injected.iter().copied())
.chain(injected.iter().cloned())
.collect::<HashSet<_>>();
Ok(Rc::new(ops))
},
@@ -64,8 +63,8 @@ pub fn collect_exported_ops(
)?;
let out = (module.items.iter())
.filter(|(_, v)| v.exported)
.map(|(k, _)| *k)
.chain(injected.iter().copied())
.map(|(k, _)| k.clone())
.chain(injected.iter().cloned())
.collect::<HashSet<_>>();
Ok(Rc::new(out))
},
@@ -74,8 +73,7 @@ pub fn collect_exported_ops(
pub fn mk_cache<'a>(
loaded: &'a LoadedSourceTable,
i: &'a Interner,
injected: &'a impl InjectedOperatorsFn,
) -> ExportedOpsCache<'a> {
Cache::new(|path, _this| collect_exported_ops(path, loaded, i, injected))
Cache::new(|path, _this| collect_exported_ops(path, loaded, injected))
}

View File

@@ -16,7 +16,7 @@ fn tree_all_ops(
module: &Module<impl Clone, impl Clone>,
ops: &mut HashSet<Tok<String>>,
) {
ops.extend(module.items.keys().copied());
ops.extend(module.items.keys().cloned());
for ent in module.items.values() {
if let ModMember::Sub(m) = &ent.member {
tree_all_ops(m, ops);
@@ -40,16 +40,14 @@ pub fn collect_ops_for(
let mut ret = HashSet::new();
tree_all_ops(tree, &mut ret);
tree.visit_all_imports(&mut |modpath, _m, import| -> ProjectResult<()> {
if let Some(n) = import.name {
ret.insert(n);
if let Some(n) = &import.name {
ret.insert(n.clone());
} else {
let path = i.expect(
import_abs_path(file, modpath, &import.path, i),
"This error should have been caught during loading",
);
ret.extend(ops_cache.find(&i.i(&path))?.iter().copied());
let path = import_abs_path(file, modpath, &import.path, i)
.expect("This error should have been caught during loading");
ret.extend(ops_cache.find(&i.i(&path))?.iter().cloned());
}
Ok(())
})?;
Ok(Rc::new(ret.into_iter().filter(|t| is_op(i.r(*t))).collect()))
Ok(Rc::new(ret.into_iter().filter(|t| is_op(&**t)).collect()))
}

View File

@@ -25,8 +25,8 @@ fn member_rec(
&preparsed.items[&name].member => ModMember::Sub;
unreachable!("This name must point to a namespace")
);
let new_body =
entv_rec(mod_stack.push(name), subprep, body, path, ops_cache, i);
let new_stack = mod_stack.push(name.clone());
let new_body = entv_rec(new_stack, subprep, body, path, ops_cache, i);
Member::Module(ModuleBlock { name, body: new_body })
},
any => any,
@@ -58,16 +58,12 @@ fn entv_rec(
.into_iter()
.flat_map(|import| {
if let Import { name: None, path } = import {
let p = i.expect(
import_abs_path(mod_path, mod_stack, &path, i),
"Should have emerged in preparsing",
);
let names = i.expect(
ops_cache.find(&i.i(&p)),
"Should have emerged in second parsing",
);
let p = import_abs_path(mod_path, mod_stack.clone(), &path, i)
.expect("Should have emerged in preparsing");
let names = (ops_cache.find(&i.i(&p)))
.expect("Should have emerged in second parsing");
let imports = (names.iter())
.map(|&n| Import { name: Some(n), path: path.clone() })
.map(|n| Import { name: Some(n.clone()), path: path.clone() })
.collect::<Vec<_>>();
Box::new(imports.into_iter()) as BoxedIter<Import>
} else {
@@ -77,10 +73,10 @@ fn entv_rec(
.collect(),
),
FileEntry::Exported(mem) => FileEntry::Exported(member_rec(
mod_stack, preparsed, mem, mod_path, ops_cache, i,
mod_stack.clone(), preparsed, mem, mod_path, ops_cache, i,
)),
FileEntry::Internal(mem) => FileEntry::Internal(member_rec(
mod_stack, preparsed, mem, mod_path, ops_cache, i,
mod_stack.clone(), preparsed, mem, mod_path, ops_cache, i,
)),
any => any,
})

View File

@@ -28,16 +28,14 @@ pub fn parse_file(
let ld = &loaded[path];
// let ops_cache = collect_ops::mk_cache(loaded, i);
let ops = collect_ops_for(path, loaded, ops_cache, i)?;
let ops_vec = ops.iter().map(|t| i.r(*t)).cloned().collect::<Vec<_>>();
let ops_vec = ops.iter().map(|t| (**t).clone()).collect::<Vec<_>>();
let ctx = parse::ParsingContext {
interner: i,
ops: &ops_vec,
file: Rc::new(i.extern_all(path)),
file: Rc::new(Interner::extern_all(path)),
};
let entries = i.expect(
parse::parse2(ld.text.as_str(), ctx),
"This error should have been caught during loading",
);
let entries = parse::parse2(ld.text.as_str(), ctx)
.expect("This error should have been caught during loading");
let with_prelude = add_prelude(entries, path, prelude);
let impnormalized =
normalize_imports(&ld.preparsed.0, with_prelude, path, ops_cache, i);

View File

@@ -15,12 +15,13 @@ fn member_rec(
i: &Interner,
) -> Member {
let prefix = (path.iter())
.copied()
.cloned()
.chain(mod_stack.iter().rev_vec_clone().into_iter())
.collect::<Vec<_>>();
match data {
Member::Module(ModuleBlock { name, body }) => {
let new_body = entv_rec(mod_stack.push(name), body, path, ops_cache, i);
let new_stack = mod_stack.push(name.clone());
let new_body = entv_rec(new_stack, body, path, ops_cache, i);
Member::Module(ModuleBlock { name, body: new_body })
},
Member::Constant(constant) => Member::Constant(Constant {
@@ -49,15 +50,15 @@ fn entv_rec(
ops_cache: &ExportedOpsCache,
i: &Interner,
) -> Vec<FileEntry> {
data
.into_iter()
.map(|fe| match fe {
FileEntry::Exported(mem) =>
FileEntry::Exported(member_rec(mod_stack, mem, path, ops_cache, i)),
FileEntry::Internal(mem) =>
FileEntry::Internal(member_rec(mod_stack, mem, path, ops_cache, i)),
(data.into_iter())
.map(|fe| {
let (mem, wrapper): (Member, fn(Member) -> FileEntry) = match fe {
FileEntry::Exported(mem) => (mem, FileEntry::Exported),
FileEntry::Internal(mem) => (mem, FileEntry::Internal),
// XXX should [FileEntry::Export] be prefixed?
any => any,
any => return any,
};
wrapper(member_rec(mod_stack.clone(), mem, path, ops_cache, i))
})
.collect()
}

View File

@@ -44,7 +44,7 @@ fn load_abs_path_rec(
return Err(UnexpectedDirectory { path: filename.to_vec() }.rc())
});
let preparsed = preparse(
filename.iter().map(|t| i.r(*t)).cloned().collect(),
Interner::extern_all(filename),
text.as_str(),
prelude,
i,
@@ -87,7 +87,7 @@ fn load_abs_path_rec(
// recurse on all files and folders within
for item in coll.iter() {
let abs_subpath = (abs_path.iter())
.copied()
.cloned()
.chain(iter::once(i.i(item)))
.collect::<Vec<_>>();
load_abs_path_rec(

View File

@@ -39,12 +39,12 @@ fn to_module(src: &[FileEntry], prelude: &[FileEntry]) -> Module<(), ()> {
FileEntry::Internal(Member::Module(ns)) => {
let member = ModMember::Sub(to_module(&ns.body, prelude));
let entry = ModEntry { exported: false, member };
Some((ns.name, entry))
Some((ns.name.clone(), entry))
},
FileEntry::Exported(Member::Module(ns)) => {
let member = ModMember::Sub(to_module(&ns.body, prelude));
let entry = ModEntry { exported: true, member };
Some((ns.name, entry))
Some((ns.name.clone(), entry))
},
_ => None,
})
@@ -57,12 +57,12 @@ fn to_module(src: &[FileEntry], prelude: &[FileEntry]) -> Module<(), ()> {
| FileEntry::Exported(Member::Module(_)) => (),
FileEntry::Export(tokv) =>
for tok in tokv {
add_export(&mut items, *tok)
add_export(&mut items, tok.clone())
},
FileEntry::Internal(Member::Constant(Constant { name, .. })) =>
add_intern(&mut items, *name),
add_intern(&mut items, name.clone()),
FileEntry::Exported(Member::Constant(Constant { name, .. })) =>
add_export(&mut items, *name),
add_export(&mut items, name.clone()),
FileEntry::Internal(Member::Rule(rule)) => {
let names = rule.collect_single_names();
for name in names {

View File

@@ -3,6 +3,7 @@
//! These structures are produced by the pipeline, processed by the macro
//! executor, and then converted to other usable formats.
use std::fmt::Display;
use std::hash::Hash;
use std::rc::Rc;
@@ -15,7 +16,7 @@ use super::interpreted;
use super::location::Location;
use super::namelike::{NameLike, VName};
use super::primitive::Primitive;
use crate::interner::{InternedDisplay, Interner, Tok};
use crate::interner::Tok;
use crate::utils::map_rc;
/// A [Clause] with associated metadata
@@ -74,7 +75,7 @@ impl Expr<VName> {
pub fn prefix(
&self,
prefix: &[Tok<String>],
except: &impl Fn(Tok<String>) -> bool,
except: &impl Fn(&Tok<String>) -> bool,
) -> Self {
Self {
value: self.value.prefix(prefix, except),
@@ -83,15 +84,9 @@ impl Expr<VName> {
}
}
impl<N: NameLike> InternedDisplay for Expr<N> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
let Expr { value, .. } = self;
value.fmt_i(f, i)?;
Ok(())
impl<N: NameLike> Display for Expr<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value.fmt(f)
}
}
@@ -110,7 +105,7 @@ pub enum PHClass {
}
/// Properties of a placeholder that matches unknown tokens in macros
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Placeholder {
/// Identifier to pair placeholders in the pattern and template
pub name: Tok<String>,
@@ -118,20 +113,14 @@ pub struct Placeholder {
pub class: PHClass,
}
impl InternedDisplay for Placeholder {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
let name = i.r(self.name);
impl Display for Placeholder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = &self.name;
match self.class {
PHClass::Scalar => write!(f, "${name}"),
PHClass::Vec { nonzero, prio } =>
if nonzero {
write!(f, "...${name}:{prio}")
} else {
write!(f, "..${name}:{prio}")
PHClass::Vec { nonzero, prio } => {
if nonzero { write!(f, "...") } else { write!(f, "..") }?;
write!(f, "${name}:{prio}")
},
}
}
@@ -307,11 +296,11 @@ impl Clause<VName> {
pub fn prefix(
&self,
prefix: &[Tok<String>],
except: &impl Fn(Tok<String>) -> bool,
except: &impl Fn(&Tok<String>) -> bool,
) -> Self {
self
.map_names(&|name| {
if except(name[0]) {
if except(&name[0]) {
return None;
}
let mut new = prefix.to_vec();
@@ -322,46 +311,27 @@ impl Clause<VName> {
}
}
fn fmt_expr_seq<'a, N: NameLike>(
it: &mut impl Iterator<Item = &'a Expr<N>>,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
for item in Itertools::intersperse(it.map(Some), None) {
match item {
Some(expr) => expr.fmt_i(f, i),
None => f.write_str(" "),
}?
}
Ok(())
}
impl<N: NameLike> InternedDisplay for Clause<N> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl<N: NameLike> Display for Clause<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::P(p) => write!(f, "{:?}", p),
Self::Name(name) => write!(f, "{}", name.to_strv(i).join("::")),
Self::Name(name) => write!(f, "{}", name.to_strv().join("::")),
Self::S(del, items) => {
f.write_str(&del.to_string())?;
fmt_expr_seq(&mut items.iter(), f, i)?;
f.write_str(match del {
let body = items.iter().join(" ");
let led = match del {
'(' => ")",
'[' => "]",
'{' => "}",
_ => "CLOSING_DELIM",
})
};
write!(f, "{del}{body}{led}")
},
Self::Lambda(arg, body) => {
f.write_str("\\")?;
fmt_expr_seq(&mut arg.iter(), f, i)?;
f.write_str(".")?;
fmt_expr_seq(&mut body.iter(), f, i)
let args = arg.iter().join(" ");
let bodys = body.iter().join(" ");
write!(f, "\\{args}.{bodys}")
},
Self::Placeh(ph) => ph.fmt_i(f, i),
Self::Placeh(ph) => ph.fmt(f),
}
}
}
@@ -382,7 +352,7 @@ impl Rule<VName> {
pub fn prefix(
&self,
prefix: &[Tok<String>],
except: &impl Fn(Tok<String>) -> bool,
except: &impl Fn(&Tok<String>) -> bool,
) -> Self {
Self {
prio: self.prio,
@@ -401,7 +371,7 @@ impl Rule<VName> {
e.search_all(&mut |e| {
if let Clause::Name(ns_name) = &e.value {
if ns_name.len() == 1 {
names.push(ns_name[0])
names.push(ns_name[0].clone())
}
}
None::<()>
@@ -411,22 +381,15 @@ impl Rule<VName> {
}
}
impl<N: NameLike> InternedDisplay for Rule<N> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
for e in self.pattern.iter() {
e.fmt_i(f, i)?;
write!(f, " ")?;
}
write!(f, "={}=>", self.prio)?;
for e in self.template.iter() {
write!(f, " ")?;
e.fmt_i(f, i)?;
}
Ok(())
impl<N: NameLike> Display for Rule<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} ={}=> {}",
self.pattern.iter().join(" "),
self.prio,
self.template.iter().join(" ")
)
}
}
@@ -439,13 +402,8 @@ pub struct Constant {
pub value: Expr<VName>,
}
impl InternedDisplay for Constant {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
write!(f, "{} := ", i.r(self.name))?;
self.value.fmt_i(f, i)
impl Display for Constant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} := {}", *self.name, self.value)
}
}

View File

@@ -4,7 +4,7 @@ use super::location::Location;
use super::{ast, postmacro};
use crate::error::ProjectError;
use crate::utils::Substack;
use crate::{Interner, Sym};
use crate::Sym;
#[derive(Debug, Clone)]
pub enum ErrorKind {
@@ -44,13 +44,13 @@ impl ProjectError for Error {
}
}
fn message(&self, _i: &Interner) -> String {
fn message(&self) -> String {
match self.kind {
ErrorKind::BadGroup(char) => format!("{} block found in the code", char),
_ => self.description().to_string(),
}
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
self.location.clone()
}
}
@@ -60,7 +60,7 @@ pub fn expr(expr: &ast::Expr<Sym>) -> Result<postmacro::Expr, Error> {
expr_rec(expr, Context::new())
}
#[derive(Clone, Copy)]
#[derive(Clone)]
struct Context<'a> {
names: Substack<'a, Sym>,
}
@@ -89,7 +89,7 @@ fn exprv_rec<'a>(
if rest.is_empty() {
return expr_rec(&v[0], ctx);
}
let f = exprv_rec(location, rest, ctx)?;
let f = exprv_rec(location, rest, ctx.clone())?;
let x = expr_rec(last, ctx)?;
let value = postmacro::Clause::Apply(Rc::new(f), Rc::new(x));
Ok(postmacro::Expr { value, location: Location::Unknown })
@@ -116,7 +116,7 @@ fn expr_rec<'a>(
return Err(Error::new(ErrorKind::Placeholder, location)),
_ => return Err(Error::new(ErrorKind::InvalidArg, location)),
};
let body_ctx = ctx.w_name(*name);
let body_ctx = ctx.w_name(name.clone());
let body = exprv_rec(location, b.as_ref(), body_ctx)?;
postmacro::Clause::Lambda(Rc::new(body))
},
@@ -127,7 +127,7 @@ fn expr_rec<'a>(
.map(|(lvl, _)| lvl);
match lvl_opt {
Some(lvl) => postmacro::Clause::LambdaArg(lvl),
None => postmacro::Clause::Constant(*name),
None => postmacro::Clause::Constant(name.clone()),
}
},
ast::Clause::S(paren, entries) => {

View File

@@ -94,7 +94,7 @@ fn from_const_tree_rec(
let mut items = HashMap::new();
let path_v = path.iter().rev_vec_clone();
for (name, item) in consts {
items.insert(name, ModEntry {
items.insert(name.clone(), ModEntry {
exported: true,
member: match item {
ConstTree::Const(c) => ModMember::Item(c),
@@ -103,8 +103,9 @@ fn from_const_tree_rec(
},
});
}
let exports =
items.keys().map(|name| (*name, pushed(&path_v, *name))).collect();
let exports = (items.keys())
.map(|name| (name.clone(), pushed(&path_v, name.clone())))
.collect();
Module {
items,
imports: vec![],

View File

@@ -3,7 +3,7 @@
//! This code may be generated to minimize the number of states external
//! functions have to define
use std::cell::RefCell;
use std::fmt::Debug;
use std::fmt::{Debug, Display};
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
@@ -13,8 +13,6 @@ use super::location::Location;
use super::path_set::PathSet;
use super::primitive::Primitive;
use super::Literal;
use crate::interner::InternedDisplay;
use crate::utils::sym2string;
use crate::Sym;
// TODO: implement Debug, Eq and Hash with cycle detection
@@ -36,19 +34,11 @@ impl Debug for Expr {
}
}
impl InternedDisplay for Expr {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &crate::interner::Interner,
) -> std::fmt::Result {
impl Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.location {
Location::Unknown => self.clause.fmt_i(f, i),
loc => {
write!(f, "{}:(", loc)?;
self.clause.fmt_i(f, i)?;
write!(f, ")")
},
Location::Unknown => write!(f, "{}", self.clause),
loc => write!(f, "{}:({})", loc, self.clause),
}
}
}
@@ -151,20 +141,16 @@ impl ExprInst {
impl Debug for ExprInst {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0.try_borrow() {
Ok(expr) => write!(f, "{:?}", expr),
Ok(expr) => write!(f, "{expr:?}"),
Err(_) => write!(f, "<borrowed>"),
}
}
}
impl InternedDisplay for ExprInst {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &crate::interner::Interner,
) -> std::fmt::Result {
impl Display for ExprInst {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0.try_borrow() {
Ok(expr) => expr.fmt_i(f, i),
Ok(expr) => write!(f, "{expr}"),
Err(_) => write!(f, "<borrowed>"),
}
}
@@ -208,32 +194,17 @@ impl Clause {
}
}
impl InternedDisplay for Clause {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &crate::interner::Interner,
) -> std::fmt::Result {
impl Display for Clause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Clause::P(p) => write!(f, "{p:?}"),
Clause::LambdaArg => write!(f, "arg"),
Clause::Apply { f: fun, x } => {
write!(f, "(")?;
fun.fmt_i(f, i)?;
write!(f, " ")?;
x.fmt_i(f, i)?;
write!(f, ")")
Clause::Apply { f: fun, x } => write!(f, "({fun} {x})"),
Clause::Lambda { args, body } => match args {
Some(path) => write!(f, "\\{path:?}.{body}"),
None => write!(f, "\\_.{body}"),
},
Clause::Lambda { args, body } => {
write!(f, "\\")?;
match args {
Some(path) => write!(f, "{path:?}")?,
None => write!(f, "_")?,
}
write!(f, ".")?;
body.fmt_i(f, i)
},
Clause::Constant(t) => write!(f, "{}", sym2string(*t, i)),
Clause::Constant(t) => write!(f, "{}", t.extern_vec().join("::")),
}
}
}

View File

@@ -20,17 +20,17 @@ pub type Sym = Tok<Vec<Tok<String>>>;
/// handled together in datastructures
pub trait NameLike: 'static + Clone + Eq + Hash {
/// Fully resolve the name for printing
fn to_strv(&self, i: &Interner) -> Vec<String>;
fn to_strv(&self) -> Vec<String>;
}
impl NameLike for Sym {
fn to_strv(&self, i: &Interner) -> Vec<String> {
i.extern_vec(*self)
fn to_strv(&self) -> Vec<String> {
self.extern_vec()
}
}
impl NameLike for VName {
fn to_strv(&self, i: &Interner) -> Vec<String> {
i.extern_all(self)
fn to_strv(&self) -> Vec<String> {
Interner::extern_all(self)
}
}

View File

@@ -40,7 +40,8 @@ fn collect_paths_cls_rec(
pub fn clause(cls: &postmacro::Clause) -> interpreted::Clause {
match cls {
postmacro::Clause::Constant(name) => interpreted::Clause::Constant(*name),
postmacro::Clause::Constant(name) =>
interpreted::Clause::Constant(name.clone()),
postmacro::Clause::P(p) => interpreted::Clause::P(p.clone()),
postmacro::Clause::Apply(f, x) =>
interpreted::Clause::Apply { f: expr(f.as_ref()), x: expr(x.as_ref()) },

View File

@@ -76,11 +76,11 @@ fn collect_consts_rec<N: NameLike>(
match &entry.member {
ModMember::Item(expr) => {
let mut name = path.iter().rev_vec_clone();
name.push(*key);
name.push(key.clone());
bag.insert(i.i(&name), expr.clone());
},
ModMember::Sub(module) =>
collect_consts_rec(path.push(*key), bag, module, i),
collect_consts_rec(path.push(key.clone()), bag, module, i),
}
}
}

View File

@@ -30,8 +30,8 @@ impl Import {
/// name if this is a specific import
pub fn nonglob_path(&self) -> Vec<Tok<String>> {
let mut path_vec = self.path.clone();
if let Some(n) = self.name {
path_vec.push(n)
if let Some(n) = &self.name {
path_vec.push(n.clone())
}
path_vec
}
@@ -98,10 +98,10 @@ pub fn normalize_namespaces(
other => Either::Right(other),
});
// Combine namespace blocks with the same name
namespaces.sort_unstable_by_key(|(_, ns)| ns.name);
namespaces.sort_unstable_by_key(|(_, ns)| ns.name.clone());
let mut lumped = namespaces
.into_iter()
.group_by(|(_, ns)| ns.name)
.group_by(|(_, ns)| ns.name.clone())
.into_iter()
.map(|(name, grp)| {
let mut any_exported = false;
@@ -119,10 +119,10 @@ pub fn normalize_namespaces(
.flat_map(|ns| ns.body.into_iter());
// Apply the function to the contents of these blocks too
let body = normalize_namespaces(Box::new(grp_src)).map_err(|mut e| {
e.push(name);
e.push(name.clone());
e
})?;
let member = Member::Module(ModuleBlock { name, body });
let member = Member::Module(ModuleBlock { name: name.clone(), body });
match (any_exported, any_internal) {
(true, true) => Err(vec![name]),
(true, false) => Ok(FileEntry::Exported(member)),
@@ -161,11 +161,11 @@ pub fn absolute_path(
Ok(new_abs.to_vec())
} else {
let new_rel =
iter::once(i.i("self")).chain(tail.iter().copied()).collect::<Vec<_>>();
iter::once(i.i("self")).chain(tail.iter().cloned()).collect::<Vec<_>>();
absolute_path(new_abs, &new_rel, i)
}
} else if *head == i.i("self") {
Ok(abs_location.iter().chain(tail.iter()).copied().collect())
Ok(abs_location.iter().chain(tail.iter()).cloned().collect())
} else {
Ok(rel_path.to_vec())
}

View File

@@ -96,11 +96,11 @@ impl<TItem: Clone, TExt: Clone> Module<TItem, TExt> {
callback: &mut impl FnMut(ModPath, &Self, &Import) -> Result<(), E>,
) -> Result<(), E> {
for import in self.imports.iter() {
callback(path, self, import)?
callback(path.clone(), self, import)?
}
for (name, entry) in self.items.iter() {
if let ModMember::Sub(module) = &entry.member {
module.visit_all_imports_rec(path.push(*name), callback)?
module.visit_all_imports_rec(path.push(name.clone()), callback)?
}
}
Ok(())

View File

@@ -64,7 +64,7 @@ fn mk_vec(pattern: &[RuleExpr]) -> VecMatcher {
let (r_sep, r_side) = right.split_at(r_sep_size);
let l_sep_size = scal_cnt(left.iter().rev());
let (l_side, l_sep) = left.split_at(left.len() - l_sep_size);
let main = VecMatcher::Placeh { key, nonzero };
let main = VecMatcher::Placeh { key: key.clone(), nonzero };
match (left, right) {
(&[], &[]) => VecMatcher::Placeh { key, nonzero },
(&[], _) => VecMatcher::Scan {
@@ -102,13 +102,13 @@ fn mk_vec(pattern: &[RuleExpr]) -> VecMatcher {
fn mk_scalar(pattern: &RuleExpr) -> ScalMatcher {
match &pattern.value {
Clause::P(p) => ScalMatcher::P(p.clone()),
Clause::Name(n) => ScalMatcher::Name(*n),
Clause::Name(n) => ScalMatcher::Name(n.clone()),
Clause::Placeh(Placeholder { name, class }) => {
debug_assert!(
!matches!(class, PHClass::Vec { .. }),
"Scalar matcher cannot be built from vector pattern"
);
ScalMatcher::Placeh(*name)
ScalMatcher::Placeh(name.clone())
},
Clause::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body))),
Clause::Lambda(arg, body) =>
@@ -122,7 +122,7 @@ mod test {
use super::mk_any;
use crate::ast::{Clause, PHClass, Placeholder};
use crate::interner::{InternedDisplay, Interner};
use crate::interner::Interner;
#[test]
fn test_scan() {
@@ -158,6 +158,6 @@ mod test {
.into_expr(),
];
let matcher = mk_any(&pattern);
println!("{}", matcher.bundle(&i));
println!("{matcher}");
}
}

View File

@@ -12,7 +12,7 @@ pub fn scal_match<'a>(
(ScalMatcher::P(p1), Clause::P(p2)) if p1 == p2 => Some(State::new()),
(ScalMatcher::Name(n1), Clause::Name(n2)) if n1 == n2 => Some(State::new()),
(ScalMatcher::Placeh(key), _) =>
Some(State::from([(*key, StateEntry::Scalar(expr))])),
Some(State::from([(key.clone(), StateEntry::Scalar(expr))])),
(ScalMatcher::S(c1, b_mat), Clause::S(c2, body)) if c1 == c2 =>
any_match(b_mat, &body[..]),
(ScalMatcher::Lambda(arg_mat, b_mat), Clause::Lambda(arg, body)) => {

View File

@@ -1,13 +1,15 @@
use std::fmt::Write;
use std::fmt::{Display, Write};
use std::rc::Rc;
use itertools::Itertools;
use super::any_match::any_match;
use super::build::mk_any;
use crate::interner::{InternedDisplay, Interner, Tok};
use crate::interner::Tok;
use crate::representations::Primitive;
use crate::rule::matcher::{Matcher, RuleExpr};
use crate::rule::state::State;
use crate::utils::{sym2string, unwrap_or, Side};
use crate::utils::Side;
use crate::Sym;
pub enum ScalMatcher {
@@ -63,115 +65,64 @@ impl Matcher for AnyMatcher {
}
}
// ################ InternedDisplay ################
// ################ Display ################
fn disp_scalv(
scalv: &[ScalMatcher],
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
let (head, tail) = unwrap_or!(scalv.split_first(); return Ok(()));
head.fmt_i(f, i)?;
for s in tail.iter() {
write!(f, " ")?;
s.fmt_i(f, i)?;
}
Ok(())
}
impl InternedDisplay for ScalMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for ScalMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::P(p) => write!(f, "{:?}", p),
Self::Placeh(n) => write!(f, "${}", i.r(*n)),
Self::Name(n) => write!(f, "{}", sym2string(*n, i)),
Self::Placeh(n) => write!(f, "${n}"),
Self::Name(n) => write!(f, "{}", n.extern_vec().join("::")),
Self::S(c, body) => {
f.write_char(*c)?;
body.fmt_i(f, i)?;
f.write_char(match c {
let pair = match c {
'(' => ')',
'[' => ']',
'{' => '}',
_ => unreachable!(),
})
};
write!(f, "{c}{body}{pair}")
},
Self::Lambda(arg, body) => {
f.write_char('\\')?;
arg.fmt_i(f, i)?;
f.write_char('.')?;
body.fmt_i(f, i)
write!(f, "\\{arg}.{body}")
},
}
}
}
impl InternedDisplay for VecMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for VecMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Placeh { key, nonzero } => {
if *nonzero {
f.write_char('.')?;
};
write!(f, "..${}", i.r(*key))
write!(f, "..${key}")
},
Self::Scan { left, sep, right, direction } => {
let arrow = match direction {
Side::Left => " <== ",
Side::Right => " ==> ",
};
write!(f, "Scan{{")?;
left.fmt_i(f, i)?;
f.write_str(arrow)?;
disp_scalv(sep, f, i)?;
f.write_str(arrow)?;
right.fmt_i(f, i)?;
write!(f, "}}")
Self::Scan { left, sep, right, direction } => match direction {
Side::Left =>
write!(f, "Scan{{{left} <== {} <== {right}}}", sep.iter().join(" ")),
Side::Right =>
write!(f, "Scan{{{left} ==> {} ==> {right}}}", sep.iter().join(" ")),
},
Self::Middle { left, left_sep, mid, right_sep, right, .. } => {
write!(f, "Middle{{")?;
left.fmt_i(f, i)?;
f.write_str("|")?;
disp_scalv(left_sep, f, i)?;
f.write_str("|")?;
mid.fmt_i(f, i)?;
f.write_str("|")?;
disp_scalv(right_sep, f, i)?;
f.write_str("|")?;
right.fmt_i(f, i)?;
write!(f, "}}")
let left_sep_s = left_sep.iter().join(" ");
let right_sep_s = right_sep.iter().join(" ");
write!(f, "Middle{{{left}|{left_sep_s}|{mid}|{right_sep_s}|{right}}}")
},
}
}
}
impl InternedDisplay for AnyMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for AnyMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Scalar(s) => {
write!(f, "(")?;
disp_scalv(s, f, i)?;
write!(f, ")")
write!(f, "({})", s.iter().join(" "))
},
Self::Vec { left, mid, right } => {
write!(f, "[")?;
disp_scalv(left, f, i)?;
write!(f, "|")?;
mid.fmt_i(f, i)?;
write!(f, "|")?;
disp_scalv(right, f, i)?;
write!(f, "]")
let lefts = left.iter().join(" ");
let rights = right.iter().join(" ");
write!(f, "[{lefts}|{mid}|{rights}]")
},
}
}
@@ -191,12 +142,8 @@ impl Matcher for VectreeMatcher {
self.0.apply(source)
}
}
impl InternedDisplay for VectreeMatcher {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
self.0.fmt_i(f, i)
impl Display for VectreeMatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}

View File

@@ -17,7 +17,7 @@ pub fn vec_match<'a>(
if *nonzero && seq.is_empty() {
return None;
}
return Some(State::from([(*key, StateEntry::Vec(seq))]));
return Some(State::from([(key.clone(), StateEntry::Vec(seq))]));
},
VecMatcher::Scan { left, sep, right, direction } => {
if seq.len() < sep.len() {

View File

@@ -64,16 +64,16 @@ fn check_rec_expr(
let typ = (*class).into();
// in a template, the type must be known and identical
// outside template (in pattern) the type must be unknown
if let Some(known) = types.insert(*name, typ) {
if let Some(known) = types.insert(name.clone(), typ) {
if !in_template {
Err(RuleError::Multiple(*name))
Err(RuleError::Multiple(name.clone()))
} else if known != typ {
Err(RuleError::ArityMismatch(*name))
Err(RuleError::ArityMismatch(name.clone()))
} else {
Ok(())
}
} else if in_template {
Err(RuleError::Missing(*name))
Err(RuleError::Missing(name.clone()))
} else {
Ok(())
}

View File

@@ -1,4 +1,4 @@
use std::fmt::{Debug, Write};
use std::fmt::{Debug, Display};
use std::format;
use std::rc::Rc;
@@ -11,7 +11,7 @@ use super::prepare_rule::prepare_rule;
use super::state::apply_exprv;
use super::{update_first_seq, RuleError, VectreeMatcher};
use crate::ast::Rule;
use crate::interner::{InternedDisplay, Interner};
use crate::interner::Interner;
use crate::Sym;
#[derive(Debug)]
@@ -21,18 +21,10 @@ pub struct CachedRule<M: Matcher> {
template: Vec<RuleExpr>,
}
impl<M: InternedDisplay + Matcher> InternedDisplay for CachedRule<M> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
for item in self.pattern.iter() {
item.fmt_i(f, i)?;
f.write_char(' ')?;
}
write!(f, "is matched by ")?;
self.matcher.fmt_i(f, i)
impl<M: Display + Matcher> Display for CachedRule<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let patterns = self.pattern.iter().join(" ");
write!(f, "{patterns} is matched by {}", self.matcher)
}
}
@@ -152,22 +144,14 @@ fn fmt_hex(num: f64) -> String {
format!("0x{:x}p{}", mantissa as i64, exponent as i64)
}
impl<M: InternedDisplay + Matcher> InternedDisplay for Repository<M> {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl<M: Display + Matcher> Display for Repository<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Repository[")?;
for (item, deps, p) in self.cache.iter() {
write!(
f,
" priority: {}\tdependencies: [{}]\n ",
fmt_hex(f64::from(*p)),
deps.iter().map(|t| i.extern_vec(*t).join("::")).join(", ")
)?;
item.fmt_i(f, i)?;
writeln!(f)?;
for (rule, deps, p) in self.cache.iter() {
let prio = fmt_hex(f64::from(*p));
let deps = deps.iter().map(|t| t.extern_vec().join("::")).join(", ");
writeln!(f, " priority: {prio}\tdependencies: [{deps}]")?;
writeln!(f, " {rule}")?;
}
write!(f, "]")
}

View File

@@ -1,16 +1,16 @@
use std::fmt;
use std::fmt::{self, Display};
use std::rc::Rc;
use hashbrown::HashSet;
use crate::ast::{self, search_all_slcs, PHClass, Placeholder, Rule};
use crate::error::{ErrorPosition, ProjectError};
use crate::interner::{InternedDisplay, Interner, Tok};
use crate::interner::Tok;
use crate::utils::BoxedIter;
use crate::{Location, Sym};
/// Various reasons why a substitution rule may be invalid
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RuleError {
/// A key is present in the template but not the pattern
Missing(Tok<String>),
@@ -33,25 +33,17 @@ impl RuleError {
}
}
impl InternedDisplay for RuleError {
fn fmt_i(&self, f: &mut fmt::Formatter<'_>, i: &Interner) -> fmt::Result {
match *self {
Self::Missing(key) => {
write!(f, "Key {:?} not in match pattern", i.r(key))
},
Self::ArityMismatch(key) => write!(
f,
"Key {:?} used inconsistently with and without ellipsis",
i.r(key)
),
Self::Multiple(key) => {
write!(f, "Key {:?} appears multiple times in match pattern", i.r(key))
},
impl Display for RuleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Missing(key) => write!(f, "Key {key} not in match pattern"),
Self::ArityMismatch(key) =>
write!(f, "Key {key} used inconsistently with and without ellipsis"),
Self::Multiple(key) =>
write!(f, "Key {key} appears multiple times in match pattern"),
Self::VecNeighbors(left, right) => write!(
f,
"Keys {:?} and {:?} are two vectorials right next to each other",
i.r(left),
i.r(right)
"Keys {left} and {right} are two vectorials right next to each other"
),
}
}
@@ -83,13 +75,13 @@ impl ProjectError for Missing {
fn description(&self) -> &str {
"A key appears in the template but not the pattern of a rule"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"The key {} appears in the template but not the pattern of this rule",
i.r(self.name)
self.name
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
(self.locations.iter())
.cloned()
@@ -124,10 +116,10 @@ impl ProjectError for Multiple {
fn description(&self) -> &str {
"A key appears multiple times in the pattern of a rule"
}
fn message(&self, i: &Interner) -> String {
format!("The key {} appears multiple times in this pattern", i.r(self.name))
fn message(&self) -> String {
format!("The key {} appears multiple times in this pattern", self.name)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
(self.locations.iter())
.cloned()
@@ -162,13 +154,13 @@ impl ProjectError for ArityMismatch {
fn description(&self) -> &str {
"A key appears with different arities in a rule"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"The key {} appears multiple times with different arities in this rule",
i.r(self.name)
self.name
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new((self.locations.iter()).cloned().map(|(location, class)| {
ErrorPosition {
location,
@@ -199,12 +191,12 @@ impl VecNeighbors {
search_all_slcs(&rule.template[..], &mut |ev| {
for pair in ev.windows(2) {
let (a, b) = (&pair[0], &pair[1]);
let a_vec = matches!(a.value, ast::Clause::Placeh(
let a_vec = matches!(&a.value, ast::Clause::Placeh(
Placeholder{ class: PHClass::Vec { .. }, name }
) if name == n1);
let b_vec = matches!(b.value, ast::Clause::Placeh(
) if name == &n1);
let b_vec = matches!(&b.value, ast::Clause::Placeh(
Placeholder{ class: PHClass::Vec { .. }, name }
) if name == n2);
) if name == &n2);
if a_vec && b_vec {
locations.insert(a.location.clone());
locations.insert(b.location.clone());
@@ -219,14 +211,13 @@ impl ProjectError for VecNeighbors {
fn description(&self) -> &str {
"Two vectorial placeholders appear next to each other"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"The keys {} and {} appear next to each other with a vectorial arity",
i.r(self.n1),
i.r(self.n2)
self.n1, self.n2
)
}
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
(self.locations.iter())
.cloned()

View File

@@ -5,13 +5,11 @@ use crate::interner::Tok;
/// Returns the name, priority and nonzero of the expression if it is
/// a vectorial placeholder
pub fn vec_attrs(expr: &RuleExpr) -> Option<(Tok<String>, u64, bool)> {
if let Clause::Placeh(Placeholder {
match expr.value.clone() {
Clause::Placeh(Placeholder {
class: PHClass::Vec { prio, nonzero },
name,
}) = expr.value
{
Some((name, prio, nonzero))
} else {
None
}) => Some((name, prio, nonzero)),
_ => None,
}
}

View File

@@ -1,7 +1,6 @@
use std::fmt::Debug;
use crate::foreign::{Atomic, AtomicReturn};
use crate::interner::InternedDisplay;
use crate::interpreter::Context;
use crate::representations::interpreted::ExprInst;
use crate::{atomic_defaults, write_fn_step, ConstTree, Interner};
@@ -19,7 +18,7 @@ struct Inspect1 {
impl Atomic for Inspect1 {
atomic_defaults!();
fn run(&self, ctx: Context) -> crate::foreign::AtomicResult {
println!("{}", self.expr_inst.bundle(ctx.interner));
println!("{}", self.expr_inst);
Ok(AtomicReturn {
clause: self.expr_inst.expr().clause.clone(),
gas: ctx.gas.map(|g| g - 1),

View File

@@ -9,6 +9,7 @@ mod num;
mod panic;
mod stl_system;
mod str;
mod state;
pub use arithmetic_error::ArithmeticError;
pub use bin::Binary;
pub use num::Numeric;

61
src/systems/stl/state.rs Normal file
View File

@@ -0,0 +1,61 @@
use std::cell::RefCell;
use std::rc::Rc;
use crate::foreign::cps_box::{const_cps, init_cps, CPSBox};
use crate::foreign::Atomic;
use crate::interpreted::ExprInst;
use crate::interpreter::HandlerTable;
use crate::systems::codegen::call;
use crate::{atomic_inert, define_fn, ConstTree, Interner};
#[derive(Debug, Clone)]
pub struct State(Rc<RefCell<ExprInst>>);
atomic_inert!(State, "a state");
#[derive(Debug, Clone)]
struct NewStateCmd;
#[derive(Debug, Clone)]
struct SetStateCmd(State);
#[derive(Debug, Clone)]
struct GetStateCmd(State);
define_fn! { SetState = |x| Ok(init_cps(2, SetStateCmd(x.try_into()?))) }
define_fn! { GetState = |x| Ok(init_cps(2, GetStateCmd(x.try_into()?))) }
fn new_state_handler<E>(cmd: &CPSBox<NewStateCmd>) -> Result<ExprInst, E> {
let (_, default, handler) = cmd.unpack2();
let state = State(Rc::new(RefCell::new(default.clone())));
Ok(call(handler.clone(), [state.atom_exi()]).wrap())
}
fn set_state_handler<E>(cmd: &CPSBox<SetStateCmd>) -> Result<ExprInst, E> {
let (SetStateCmd(state), value, handler) = cmd.unpack2();
*state.0.as_ref().borrow_mut() = value.clone();
Ok(handler.clone())
}
fn get_state_handler<E>(cmd: &CPSBox<GetStateCmd>) -> Result<ExprInst, E> {
let (GetStateCmd(state), handler) = cmd.unpack1();
Ok(call(handler.clone(), [state.0.as_ref().borrow().clone()]).wrap())
}
pub fn state_handlers() -> HandlerTable<'static> {
let mut handlers = HandlerTable::new();
handlers.register(new_state_handler);
handlers.register(get_state_handler);
handlers.register(set_state_handler);
handlers
}
pub fn state_lib(i: &Interner) -> ConstTree {
ConstTree::namespace(
[i.i("state")],
ConstTree::tree([
(i.i("new_state"), const_cps(2, NewStateCmd)),
(i.i("get_state"), ConstTree::xfn(GetState)),
(i.i("set_state"), ConstTree::xfn(SetState)),
]),
)
}

View File

@@ -8,10 +8,10 @@ use super::conv::conv;
use super::inspect::inspect;
use super::num::num;
use super::panic::panic;
use super::state::{state_handlers, state_lib};
use super::str::str;
use crate::facade::{IntoSystem, System};
use crate::interner::Interner;
use crate::interpreter::HandlerTable;
use crate::pipeline::file_loader::embed_to_map;
use crate::sourcefile::{FileEntry, Import};
@@ -33,7 +33,8 @@ struct StlEmbed;
impl IntoSystem<'static> for StlConfig {
fn into_system(self, i: &Interner) -> System<'static> {
let pure_fns = conv(i) + bool(i) + str(i) + num(i) + bin(i) + panic(i);
let pure_fns =
conv(i) + bool(i) + str(i) + num(i) + bin(i) + panic(i) + state_lib(i);
let mk_impure_fns = || inspect(i);
let fns = if self.impure { pure_fns + mk_impure_fns() } else { pure_fns };
System {
@@ -44,7 +45,7 @@ impl IntoSystem<'static> for StlConfig {
path: vec![i.i("std"), i.i("prelude")],
name: None,
}])],
handlers: HandlerTable::new(),
handlers: state_handlers(),
}
}
}

View File

@@ -2,7 +2,6 @@ mod cache;
mod delete_cell;
mod event_poller;
mod iter_find;
mod print_nname;
mod pushed;
mod rc_to_owned;
mod replace_first;
@@ -15,7 +14,6 @@ pub mod thread_pool;
mod unwrap_or;
pub use cache::Cache;
pub use print_nname::sym2string;
pub use pushed::pushed;
pub use rc_to_owned::{map_rc, rc_to_owned};
pub use replace_first::replace_first;

View File

@@ -1,9 +0,0 @@
use itertools::Itertools;
use crate::interner::Interner;
use crate::Sym;
/// Print symbols to :: delimited strings
pub fn sym2string(t: Sym, i: &Interner) -> String {
i.r(t).iter().map(|t| i.r(*t)).join("::")
}