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

View File

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

View File

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

View File

@@ -21,21 +21,23 @@ impl ProjectError for NotExported {
fn description(&self) -> &str { fn description(&self) -> &str {
"An import refers to a symbol that exists but isn't exported" "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( Box::new(
[ [
ErrorPosition { ErrorPosition {
location: Location::File(Rc::new(i.extern_all(&self.file))), location: Location::File(Rc::new(Interner::extern_all(&self.file))),
message: Some(format!( message: Some(format!(
"{} isn't exported", "{} isn't exported",
i.extern_all(&self.subpath).join("::") Interner::extern_all(&self.subpath).join("::")
)), )),
}, },
ErrorPosition { 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!( message: Some(format!(
"{} cannot see this symbol", "{} 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 { ) -> Self {
let last_mod = let last_mod =
orig.walk_ref(&path[..e.pos], false).expect("error occured on next step"); 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 { if let Some(file) = &last_mod.extra.file {
Self { Self {
source: Some(source.to_vec()), source: Some(source.to_vec()),
@@ -57,14 +57,14 @@ impl ProjectError for NotFound {
fn description(&self) -> &str { fn description(&self) -> &str {
"an import refers to a nonexistent module" "an import refers to a nonexistent module"
} }
fn message(&self, i: &Interner) -> String { fn message(&self) -> String {
format!( format!(
"module {} in {} was not found", "module {} in {} was not found",
i.extern_all(&self.subpath).join("::"), Interner::extern_all(&self.subpath).join("::"),
i.extern_all(&self.file).join("/"), Interner::extern_all(&self.file).join("/"),
) )
} }
fn one_position(&self, i: &Interner) -> crate::Location { fn one_position(&self) -> crate::Location {
Location::File(Rc::new(i.extern_all(&self.file))) Location::File(Rc::new(Interner::extern_all(&self.file)))
} }
} }

View File

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

View File

@@ -1,10 +1,10 @@
use std::fmt::Debug;
use std::fmt::Display;
use std::rc::Rc; use std::rc::Rc;
use crate::interner::InternedDisplay;
use crate::representations::location::Location; use crate::representations::location::Location;
use crate::utils::iter::box_once; use crate::utils::iter::box_once;
use crate::utils::BoxedIter; use crate::utils::BoxedIter;
use crate::Interner;
/// A point of interest in resolving the error, such as the point where /// A point of interest in resolving the error, such as the point where
/// processing got stuck, a command that is likely to be incorrect /// 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 /// A general description of this type of error
fn description(&self) -> &str; fn description(&self) -> &str;
/// A formatted message that includes specific parameters /// A formatted message that includes specific parameters
fn message(&self, _i: &Interner) -> String { fn message(&self) -> String {
self.description().to_string() self.description().to_string()
} }
/// Code positions relevant to this error. If you don't implement this, you /// Code positions relevant to this error. If you don't implement this, you
/// must implement [ProjectError::one_position] /// must implement [ProjectError::one_position]
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> { fn positions(&self) -> BoxedIter<ErrorPosition> {
box_once(ErrorPosition { location: self.one_position(i), message: None }) box_once(ErrorPosition { location: self.one_position(), message: None })
} }
/// Short way to provide a single location. If you don't implement this, you /// Short way to provide a single location. If you don't implement this, you
/// must implement [ProjectError::positions] /// must implement [ProjectError::positions]
fn one_position(&self, _i: &Interner) -> Location { fn one_position(&self) -> Location {
unimplemented!() 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
@@ -44,15 +44,11 @@ pub trait ProjectError {
} }
} }
impl InternedDisplay for dyn ProjectError { impl Display for dyn ProjectError {
fn fmt_i( fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
let description = self.description(); let description = self.description();
let message = self.message(i); let message = self.message();
let positions = self.positions(i); let positions = self.positions();
writeln!(f, "Project error: {description}\n{message}")?; writeln!(f, "Project error: {description}\n{message}")?;
for ErrorPosition { location, message } in positions { for ErrorPosition { location, message } in positions {
writeln!( 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. /// 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. /// This is the type of result most commonly returned by pre-run operations.
pub type ProjectResult<T> = Result<T, Rc<dyn ProjectError>>; 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 \ "an import path starts with more `super` segments than the current \
module's absolute path" module's absolute path"
} }
fn message(&self, i: &Interner) -> String { fn message(&self) -> String {
format!( format!(
"path {} in {} contains too many `super` steps.", "path {} in {} contains too many `super` steps.",
i.extern_all(&self.path).join("::"), Interner::extern_all(&self.path).join("::"),
i.extern_all(&self.offender_mod).join("::") Interner::extern_all(&self.offender_mod).join("::")
) )
} }
fn one_position(&self, i: &Interner) -> Location { fn one_position(&self) -> Location {
Location::File(Rc::new(i.extern_all(&self.offender_file))) 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 \ "A stage that deals specifically with code encountered a path that refers \
to a directory" to a directory"
} }
fn one_position(&self, i: &Interner) -> crate::Location { fn one_position(&self) -> crate::Location {
Location::File(Rc::new(i.extern_all(&self.path))) Location::File(Rc::new(Interner::extern_all(&self.path)))
} }
fn message(&self, i: &Interner) -> String { fn message(&self) -> 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",
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 { 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 message(&self, i: &Interner) -> String { fn message(&self) -> String {
format!( format!(
"{} is opened multiple times with different visibilities", "{} 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()) Location::File(self.file.clone())
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,9 +5,9 @@
mod monotype; mod monotype;
mod multitype; mod multitype;
mod token; mod token;
mod traits; // mod traits;
pub use monotype::TypedInterner; pub use monotype::TypedInterner;
pub use multitype::Interner; pub use multitype::Interner;
pub use token::Tok; 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::borrow::Borrow;
use std::cell::RefCell; use std::cell::RefCell;
use std::hash::{BuildHasher, Hash}; use std::hash::{BuildHasher, Hash};
use std::num::NonZeroU32; use std::rc::Rc;
use hashbrown::HashMap; 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 /// Lasso but much simpler, in part because not much can be known about the
/// type. /// type.
pub struct TypedInterner<T: 'static + Eq + Hash + Clone> { pub struct TypedInterner<T: 'static + Eq + Hash + Clone> {
tokens: RefCell<HashMap<&'static T, Tok<T>>>, tokens: RefCell<HashMap<Rc<T>, Tok<T>>>,
values: RefCell<Vec<(&'static T, bool)>>,
} }
impl<T: Eq + Hash + Clone> TypedInterner<T> { impl<T: Eq + Hash + Clone> TypedInterner<T> {
/// Create a fresh interner instance /// Create a fresh interner instance
pub fn new() -> Self { pub fn new() -> Rc<Self> {
Self { Rc::new(Self { tokens: RefCell::new(HashMap::new()) })
tokens: RefCell::new(HashMap::new()),
values: RefCell::new(Vec::new()),
}
} }
/// Intern an object, returning a token /// 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 where
T: Borrow<Q>, T: Borrow<Q>,
{ {
@@ -34,65 +33,11 @@ impl<T: Eq + Hash + Clone> TypedInterner<T> {
.raw_entry_mut() .raw_entry_mut()
.from_hash(hash, |k| <T as Borrow<Q>>::borrow(k) == q); .from_hash(hash, |k| <T as Borrow<Q>>::borrow(k) == q);
let kv = raw_entry.or_insert_with(|| { let kv = raw_entry.or_insert_with(|| {
let mut values = self.values.borrow_mut(); let keyrc = Rc::new(q.to_owned());
let uniq_key: NonZeroU32 = let token = Tok::<T>::new(keyrc.clone(), Rc::downgrade(self));
(values.len() as u32 + 1u32).try_into().expect("can never be zero"); (keyrc, token)
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)
}); });
*kv.1 kv.1.clone()
}
/// 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()) };
}
} }
} }

View File

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

View File

@@ -1,66 +1,94 @@
use std::cmp::PartialEq; use std::cmp::PartialEq;
use std::fmt::Debug; use std::fmt::{Debug, Display};
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::num::NonZeroUsize;
use std::num::NonZeroU32; 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 /// 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 /// 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 /// token with an interner other than the one that created it, but this is
/// currently not enforced. /// currently not enforced.
pub struct Tok<T> { #[derive(Clone)]
id: NonZeroU32, pub struct Tok<T: Eq + Hash + Clone + 'static> {
phantom_data: PhantomData<T>, data: Rc<T>,
interner: Weak<TypedInterner<T>>,
} }
impl<T> Tok<T> { impl<T: Eq + Hash + Clone + 'static> Tok<T> {
/// Wrap an ID number into a token /// Create a new token. Used exclusively by the interner
pub fn from_id(id: NonZeroU32) -> Self { pub(crate) fn new(data: Rc<T>, interner: Weak<TypedInterner<T>>) -> Self {
Self { id, phantom_data: PhantomData } Self { data, interner }
} }
/// Take the ID number out of a token /// Take the ID number out of a token
pub fn into_id(self) -> NonZeroU32 { pub fn id(&self) -> NonZeroUsize {
self.id ((self.data.as_ref() as *const T as usize).try_into())
.expect("Pointer can always be cast to nonzero")
} }
/// Cast into usize /// Cast into usize
pub fn into_usize(self) -> usize { pub fn usize(&self) -> usize {
let zero: u32 = self.id.into(); self.id().into()
zero as usize }
///
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 { 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: Eq + Hash + Clone + Display + 'static> Display for Tok<T> {
impl<T> Clone for Tok<T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn clone(&self) -> Self { write!(f, "{}", *self)
Self { id: self.id, phantom_data: PhantomData }
} }
} }
impl<T> Eq for Tok<T> {} impl<T: Eq + Hash + Clone + 'static> Eq for Tok<T> {}
impl<T> PartialEq for Tok<T> { impl<T: Eq + Hash + Clone + 'static> PartialEq for Tok<T> {
fn eq(&self, other: &Self) -> bool { 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 { 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> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other)) 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) { 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) { if let Some(sym) = ctx.symbols.get(name) {
Ok((Clause::Apply { f: sym.clone(), x }, (ctx.gas, false))) Ok((Clause::Apply { f: sym.clone(), x }, (ctx.gas, false)))
} else { } else {
Err(RuntimeError::MissingSymbol(*name, loc.clone())) Err(RuntimeError::MissingSymbol(name.clone(), loc.clone()))
}, },
Clause::P(Primitive::Atom(atom)) => { Clause::P(Primitive::Atom(atom)) => {
// take a step in expanding atom // take a step in expanding atom

View File

@@ -1,7 +1,7 @@
use std::fmt::Display;
use std::rc::Rc; use std::rc::Rc;
use crate::foreign::ExternError; use crate::foreign::ExternError;
use crate::interner::InternedDisplay;
use crate::representations::interpreted::ExprInst; use crate::representations::interpreted::ExprInst;
use crate::{Location, Sym}; use crate::{Location, Sym};
@@ -22,12 +22,8 @@ impl From<Rc<dyn ExternError>> for RuntimeError {
} }
} }
impl InternedDisplay for RuntimeError { impl Display for RuntimeError {
fn fmt_i( fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
&self,
f: &mut std::fmt::Formatter<'_>,
i: &crate::Interner,
) -> std::fmt::Result {
match self { match self {
Self::Extern(e) => write!(f, "Error in external function: {e}"), Self::Extern(e) => write!(f, "Error in external function: {e}"),
Self::NonFunctionApplication(expr) => { Self::NonFunctionApplication(expr) => {
@@ -37,7 +33,7 @@ impl InternedDisplay for RuntimeError {
write!( write!(
f, f,
"{}, called at {loc} is not loaded", "{}, 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(); i = clause.clone();
}, },
Clause::Constant(c) => { Clause::Constant(c) => {
let symval = (ctx.symbols.get(c)) let symval = (ctx.symbols.get(c)).ok_or_else(|| {
.ok_or_else(|| RuntimeError::MissingSymbol(*c, loc.clone()))?; RuntimeError::MissingSymbol(c.clone(), loc.clone())
})?;
ctx.gas = ctx.gas.map(|g| g - 1); // cost of lookup ctx.gas = ctx.gas.map(|g| g - 1); // cost of lookup
i = symval.expr().clause.clone(); i = symval.expr().clause.clone();
}, },

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,10 +24,10 @@ 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 one_position(&self, _i: &Interner) -> crate::Location { fn one_position(&self) -> crate::Location {
Location::File(Rc::new(self.path.clone())) Location::File(Rc::new(self.path.clone()))
} }
fn message(&self, _i: &Interner) -> String { fn message(&self) -> String {
format!("File: {}\nDirectory: {}", self.file, self.dir) 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 /// 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 { 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) 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] /// Generates a cached file loader for a [RustEmbed]
pub fn mk_embed_cache<'a, T: 'static + RustEmbed>( pub fn mk_embed_cache<T: 'static + RustEmbed>(
ext: &'a str, ext: &str,
i: &'a Interner, ) -> Cache<'_, Vec<Stok>, IOResult> {
) -> Cache<'a, Vec<Stok>, IOResult> {
Cache::new(move |vname: VName, _this| -> 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) load_embed::<T>(&path, ext)
}) })
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,7 @@ use hashbrown::HashSet;
use trait_set::trait_set; use trait_set::trait_set;
use crate::error::{NotFound, ProjectError, ProjectResult}; use crate::error::{NotFound, ProjectError, ProjectResult};
use crate::interner::{Interner, Tok}; use crate::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, Cache}; use crate::utils::{split_max_prefix, Cache};
@@ -28,22 +28,21 @@ fn coprefix<T: Eq>(
pub fn collect_exported_ops( pub fn collect_exported_ops(
path: Sym, path: Sym,
loaded: &LoadedSourceTable, loaded: &LoadedSourceTable,
i: &Interner,
injected: &impl InjectedOperatorsFn, injected: &impl InjectedOperatorsFn,
) -> OpsResult { ) -> OpsResult {
let injected = injected(path).unwrap_or_else(|| Rc::new(HashSet::new())); let injected =
let path_s = &i.r(path)[..]; injected(path.clone()).unwrap_or_else(|| Rc::new(HashSet::new()));
match split_max_prefix(path_s, &|n| loaded.contains_key(n)) { match split_max_prefix(&path, &|n| loaded.contains_key(n)) {
None => { None => {
let ops = (loaded.keys()) let ops = (loaded.keys())
.filter_map(|modname| { .filter_map(|modname| {
if path_s.len() == coprefix(path_s.iter(), modname.iter()) { if path.len() == coprefix(path.iter(), modname.iter()) {
Some(modname[path_s.len()]) Some(modname[path.len()].clone())
} else { } else {
None None
} }
}) })
.chain(injected.iter().copied()) .chain(injected.iter().cloned())
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
Ok(Rc::new(ops)) Ok(Rc::new(ops))
}, },
@@ -64,8 +63,8 @@ pub fn collect_exported_ops(
)?; )?;
let out = (module.items.iter()) let out = (module.items.iter())
.filter(|(_, v)| v.exported) .filter(|(_, v)| v.exported)
.map(|(k, _)| *k) .map(|(k, _)| k.clone())
.chain(injected.iter().copied()) .chain(injected.iter().cloned())
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
Ok(Rc::new(out)) Ok(Rc::new(out))
}, },
@@ -74,8 +73,7 @@ pub fn collect_exported_ops(
pub fn mk_cache<'a>( pub fn mk_cache<'a>(
loaded: &'a LoadedSourceTable, loaded: &'a LoadedSourceTable,
i: &'a Interner,
injected: &'a impl InjectedOperatorsFn, injected: &'a impl InjectedOperatorsFn,
) -> ExportedOpsCache<'a> { ) -> 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>, module: &Module<impl Clone, impl Clone>,
ops: &mut HashSet<Tok<String>>, ops: &mut HashSet<Tok<String>>,
) { ) {
ops.extend(module.items.keys().copied()); ops.extend(module.items.keys().cloned());
for ent in module.items.values() { for ent in module.items.values() {
if let ModMember::Sub(m) = &ent.member { if let ModMember::Sub(m) = &ent.member {
tree_all_ops(m, ops); tree_all_ops(m, ops);
@@ -40,16 +40,14 @@ pub fn collect_ops_for(
let mut ret = HashSet::new(); let mut ret = HashSet::new();
tree_all_ops(tree, &mut ret); tree_all_ops(tree, &mut ret);
tree.visit_all_imports(&mut |modpath, _m, import| -> ProjectResult<()> { tree.visit_all_imports(&mut |modpath, _m, import| -> ProjectResult<()> {
if let Some(n) = import.name { if let Some(n) = &import.name {
ret.insert(n); ret.insert(n.clone());
} else { } else {
let path = i.expect( let path = import_abs_path(file, modpath, &import.path, i)
import_abs_path(file, modpath, &import.path, i), .expect("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().cloned());
);
ret.extend(ops_cache.find(&i.i(&path))?.iter().copied());
} }
Ok(()) 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; &preparsed.items[&name].member => ModMember::Sub;
unreachable!("This name must point to a namespace") unreachable!("This name must point to a namespace")
); );
let new_body = let new_stack = mod_stack.push(name.clone());
entv_rec(mod_stack.push(name), subprep, body, path, ops_cache, i); let new_body = entv_rec(new_stack, subprep, body, path, ops_cache, i);
Member::Module(ModuleBlock { name, body: new_body }) Member::Module(ModuleBlock { name, body: new_body })
}, },
any => any, any => any,
@@ -58,16 +58,12 @@ fn entv_rec(
.into_iter() .into_iter()
.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 = import_abs_path(mod_path, mod_stack.clone(), &path, i)
import_abs_path(mod_path, mod_stack, &path, i), .expect("Should have emerged in preparsing");
"Should have emerged in preparsing", let names = (ops_cache.find(&i.i(&p)))
); .expect("Should have emerged in second parsing");
let names = i.expect(
ops_cache.find(&i.i(&p)),
"Should have emerged in second parsing",
);
let imports = (names.iter()) 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<_>>(); .collect::<Vec<_>>();
Box::new(imports.into_iter()) as BoxedIter<Import> Box::new(imports.into_iter()) as BoxedIter<Import>
} else { } else {
@@ -77,10 +73,10 @@ fn entv_rec(
.collect(), .collect(),
), ),
FileEntry::Exported(mem) => FileEntry::Exported(member_rec( 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( 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, any => any,
}) })

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -40,7 +40,8 @@ fn collect_paths_cls_rec(
pub fn clause(cls: &postmacro::Clause) -> interpreted::Clause { pub fn clause(cls: &postmacro::Clause) -> interpreted::Clause {
match cls { 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::P(p) => interpreted::Clause::P(p.clone()),
postmacro::Clause::Apply(f, x) => postmacro::Clause::Apply(f, x) =>
interpreted::Clause::Apply { f: expr(f.as_ref()), x: expr(x.as_ref()) }, 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 { match &entry.member {
ModMember::Item(expr) => { ModMember::Item(expr) => {
let mut name = path.iter().rev_vec_clone(); let mut name = path.iter().rev_vec_clone();
name.push(*key); name.push(key.clone());
bag.insert(i.i(&name), expr.clone()); bag.insert(i.i(&name), expr.clone());
}, },
ModMember::Sub(module) => 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 /// name if this is a specific import
pub fn nonglob_path(&self) -> Vec<Tok<String>> { pub fn nonglob_path(&self) -> Vec<Tok<String>> {
let mut path_vec = 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.clone())
} }
path_vec path_vec
} }
@@ -98,10 +98,10 @@ pub fn normalize_namespaces(
other => Either::Right(other), other => Either::Right(other),
}); });
// Combine namespace blocks with the same name // 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 let mut lumped = namespaces
.into_iter() .into_iter()
.group_by(|(_, ns)| ns.name) .group_by(|(_, ns)| ns.name.clone())
.into_iter() .into_iter()
.map(|(name, grp)| { .map(|(name, grp)| {
let mut any_exported = false; let mut any_exported = false;
@@ -119,10 +119,10 @@ pub fn normalize_namespaces(
.flat_map(|ns| ns.body.into_iter()); .flat_map(|ns| ns.body.into_iter());
// Apply the function to the contents of these blocks too // Apply the function to the contents of these blocks too
let body = normalize_namespaces(Box::new(grp_src)).map_err(|mut e| { let body = normalize_namespaces(Box::new(grp_src)).map_err(|mut e| {
e.push(name); e.push(name.clone());
e e
})?; })?;
let member = Member::Module(ModuleBlock { name, body }); let member = Member::Module(ModuleBlock { name: name.clone(), body });
match (any_exported, any_internal) { match (any_exported, any_internal) {
(true, true) => Err(vec![name]), (true, true) => Err(vec![name]),
(true, false) => Ok(FileEntry::Exported(member)), (true, false) => Ok(FileEntry::Exported(member)),
@@ -161,11 +161,11 @@ pub fn absolute_path(
Ok(new_abs.to_vec()) Ok(new_abs.to_vec())
} else { } else {
let new_rel = 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) absolute_path(new_abs, &new_rel, i)
} }
} else if *head == i.i("self") { } 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 { } else {
Ok(rel_path.to_vec()) 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>, callback: &mut impl FnMut(ModPath, &Self, &Import) -> Result<(), E>,
) -> Result<(), E> { ) -> Result<(), E> {
for import in self.imports.iter() { for import in self.imports.iter() {
callback(path, self, import)? callback(path.clone(), self, import)?
} }
for (name, entry) in self.items.iter() { for (name, entry) in self.items.iter() {
if let ModMember::Sub(module) = &entry.member { 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(()) 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 (r_sep, r_side) = right.split_at(r_sep_size);
let l_sep_size = scal_cnt(left.iter().rev()); let l_sep_size = scal_cnt(left.iter().rev());
let (l_side, l_sep) = left.split_at(left.len() - l_sep_size); 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) { match (left, right) {
(&[], &[]) => VecMatcher::Placeh { key, nonzero }, (&[], &[]) => VecMatcher::Placeh { key, nonzero },
(&[], _) => VecMatcher::Scan { (&[], _) => VecMatcher::Scan {
@@ -102,13 +102,13 @@ fn mk_vec(pattern: &[RuleExpr]) -> VecMatcher {
fn mk_scalar(pattern: &RuleExpr) -> ScalMatcher { fn mk_scalar(pattern: &RuleExpr) -> ScalMatcher {
match &pattern.value { match &pattern.value {
Clause::P(p) => ScalMatcher::P(p.clone()), 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 }) => { Clause::Placeh(Placeholder { name, class }) => {
debug_assert!( debug_assert!(
!matches!(class, PHClass::Vec { .. }), !matches!(class, PHClass::Vec { .. }),
"Scalar matcher cannot be built from vector pattern" "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::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body))),
Clause::Lambda(arg, body) => Clause::Lambda(arg, body) =>
@@ -122,7 +122,7 @@ mod test {
use super::mk_any; use super::mk_any;
use crate::ast::{Clause, PHClass, Placeholder}; use crate::ast::{Clause, PHClass, Placeholder};
use crate::interner::{InternedDisplay, Interner}; use crate::interner::Interner;
#[test] #[test]
fn test_scan() { fn test_scan() {
@@ -158,6 +158,6 @@ mod test {
.into_expr(), .into_expr(),
]; ];
let matcher = mk_any(&pattern); 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::P(p1), Clause::P(p2)) if p1 == p2 => Some(State::new()),
(ScalMatcher::Name(n1), Clause::Name(n2)) if n1 == n2 => Some(State::new()), (ScalMatcher::Name(n1), Clause::Name(n2)) if n1 == n2 => Some(State::new()),
(ScalMatcher::Placeh(key), _) => (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 => (ScalMatcher::S(c1, b_mat), Clause::S(c2, body)) if c1 == c2 =>
any_match(b_mat, &body[..]), any_match(b_mat, &body[..]),
(ScalMatcher::Lambda(arg_mat, b_mat), Clause::Lambda(arg, 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 std::rc::Rc;
use itertools::Itertools;
use super::any_match::any_match; use super::any_match::any_match;
use super::build::mk_any; use super::build::mk_any;
use crate::interner::{InternedDisplay, Interner, Tok}; use crate::interner::Tok;
use crate::representations::Primitive; use crate::representations::Primitive;
use crate::rule::matcher::{Matcher, RuleExpr}; use crate::rule::matcher::{Matcher, RuleExpr};
use crate::rule::state::State; use crate::rule::state::State;
use crate::utils::{sym2string, unwrap_or, Side}; use crate::utils::Side;
use crate::Sym; use crate::Sym;
pub enum ScalMatcher { pub enum ScalMatcher {
@@ -63,115 +65,64 @@ impl Matcher for AnyMatcher {
} }
} }
// ################ InternedDisplay ################ // ################ Display ################
fn disp_scalv( impl Display for ScalMatcher {
scalv: &[ScalMatcher], fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
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 {
match self { match self {
Self::P(p) => write!(f, "{:?}", p), Self::P(p) => write!(f, "{:?}", p),
Self::Placeh(n) => write!(f, "${}", i.r(*n)), Self::Placeh(n) => write!(f, "${n}"),
Self::Name(n) => write!(f, "{}", sym2string(*n, i)), Self::Name(n) => write!(f, "{}", n.extern_vec().join("::")),
Self::S(c, body) => { Self::S(c, body) => {
f.write_char(*c)?; let pair = match c {
body.fmt_i(f, i)?;
f.write_char(match c {
'(' => ')', '(' => ')',
'[' => ']', '[' => ']',
'{' => '}', '{' => '}',
_ => unreachable!(), _ => unreachable!(),
}) };
write!(f, "{c}{body}{pair}")
}, },
Self::Lambda(arg, body) => { Self::Lambda(arg, body) => {
f.write_char('\\')?; write!(f, "\\{arg}.{body}")
arg.fmt_i(f, i)?;
f.write_char('.')?;
body.fmt_i(f, i)
}, },
} }
} }
} }
impl InternedDisplay for VecMatcher { impl Display for VecMatcher {
fn fmt_i( fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
match self { match self {
Self::Placeh { key, nonzero } => { Self::Placeh { key, nonzero } => {
if *nonzero { if *nonzero {
f.write_char('.')?; f.write_char('.')?;
}; };
write!(f, "..${}", i.r(*key)) write!(f, "..${key}")
}, },
Self::Scan { left, sep, right, direction } => { Self::Scan { left, sep, right, direction } => match direction {
let arrow = match direction { Side::Left =>
Side::Left => " <== ", write!(f, "Scan{{{left} <== {} <== {right}}}", sep.iter().join(" ")),
Side::Right => " ==> ", Side::Right =>
}; write!(f, "Scan{{{left} ==> {} ==> {right}}}", sep.iter().join(" ")),
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::Middle { left, left_sep, mid, right_sep, right, .. } => { Self::Middle { left, left_sep, mid, right_sep, right, .. } => {
write!(f, "Middle{{")?; let left_sep_s = left_sep.iter().join(" ");
left.fmt_i(f, i)?; let right_sep_s = right_sep.iter().join(" ");
f.write_str("|")?; write!(f, "Middle{{{left}|{left_sep_s}|{mid}|{right_sep_s}|{right}}}")
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, "}}")
}, },
} }
} }
} }
impl InternedDisplay for AnyMatcher { impl Display for AnyMatcher {
fn fmt_i( fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
match self { match self {
Self::Scalar(s) => { Self::Scalar(s) => {
write!(f, "(")?; write!(f, "({})", s.iter().join(" "))
disp_scalv(s, f, i)?;
write!(f, ")")
}, },
Self::Vec { left, mid, right } => { Self::Vec { left, mid, right } => {
write!(f, "[")?; let lefts = left.iter().join(" ");
disp_scalv(left, f, i)?; let rights = right.iter().join(" ");
write!(f, "|")?; write!(f, "[{lefts}|{mid}|{rights}]")
mid.fmt_i(f, i)?;
write!(f, "|")?;
disp_scalv(right, f, i)?;
write!(f, "]")
}, },
} }
} }
@@ -191,12 +142,8 @@ impl Matcher for VectreeMatcher {
self.0.apply(source) self.0.apply(source)
} }
} }
impl InternedDisplay for VectreeMatcher { impl Display for VectreeMatcher {
fn fmt_i( fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
&self, self.0.fmt(f)
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
self.0.fmt_i(f, i)
} }
} }

View File

@@ -17,7 +17,7 @@ pub fn vec_match<'a>(
if *nonzero && seq.is_empty() { if *nonzero && seq.is_empty() {
return None; 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 } => { VecMatcher::Scan { left, sep, right, direction } => {
if seq.len() < sep.len() { if seq.len() < sep.len() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,6 @@ mod cache;
mod delete_cell; mod delete_cell;
mod event_poller; mod event_poller;
mod iter_find; mod iter_find;
mod print_nname;
mod pushed; mod pushed;
mod rc_to_owned; mod rc_to_owned;
mod replace_first; mod replace_first;
@@ -15,7 +14,6 @@ pub mod thread_pool;
mod unwrap_or; mod unwrap_or;
pub use cache::Cache; pub use cache::Cache;
pub use print_nname::sym2string;
pub use pushed::pushed; pub use pushed::pushed;
pub use rc_to_owned::{map_rc, rc_to_owned}; pub use rc_to_owned::{map_rc, rc_to_owned};
pub use replace_first::replace_first; 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("::")
}