Skip to content

Commit

Permalink
Converted Interner to work with Rc-s
Browse files Browse the repository at this point in the history
- Interner no longer contains unsafe code
- Tokens now hold a reference to the value they represent directly

This will enable many future improvements
  • Loading branch information
lbfalvy committed Aug 19, 2023
1 parent ab0b57b commit 0b887ce
Show file tree
Hide file tree
Showing 62 changed files with 592 additions and 762 deletions.
37 changes: 17 additions & 20 deletions src/bin/orcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::process;
use clap::Parser;
use itertools::Itertools;
use orchidlang::facade::{Environment, PreMacro};
use orchidlang::interner::InternedDisplay;
use orchidlang::systems::stl::StlConfig;
use orchidlang::systems::{io_system, AsynchConfig, IOStream};
use orchidlang::{ast, interpreted, interpreter, Interner, Sym, VName};
Expand Down Expand Up @@ -70,36 +69,34 @@ pub fn to_vname(data: &str, i: &Interner) -> VName {
data.split("::").map(|s| i.i(s)).collect::<Vec<_>>()
}

fn print_for_debug(e: &ast::Expr<Sym>, i: &Interner) {
fn print_for_debug(e: &ast::Expr<Sym>) {
print!(
"code: {}\nglossary: {}",
e.bundle(i),
e,
(e.value.collect_names().into_iter())
.map(|t| i.extern_vec(t).join("::"))
.map(|t| t.iter().join("::"))
.join(", ")
)
}

/// A little utility to step through the resolution of a macro set
pub fn macro_debug(premacro: PreMacro, sym: Sym, i: &Interner) {
pub fn macro_debug(premacro: PreMacro, sym: Sym) {
let (mut code, location) = (premacro.consts.get(&sym))
.unwrap_or_else(|| {
panic!(
"Symbol {} not found\nvalid symbols: \n\t{}\n",
i.extern_vec(sym).join("::"),
(premacro.consts.keys())
.map(|t| i.extern_vec(*t).join("::"))
.join("\n\t")
sym.iter().join("::"),
(premacro.consts.keys()).map(|t| t.iter().join("::")).join("\n\t")
)
})
.clone();
println!(
"Debugging macros in {} defined at {}.
Initial state: ",
i.extern_vec(sym).join("::"),
sym.iter().join("::"),
location
);
print_for_debug(&code, i);
print_for_debug(&code);
let mut steps = premacro.step(sym).enumerate();
loop {
let (cmd, _) = cmd_prompt("\ncmd> ").unwrap();
Expand All @@ -108,12 +105,12 @@ pub fn macro_debug(premacro: PreMacro, sym: Sym, i: &Interner) {
if let Some((idx, c)) = steps.next() {
code = c;
print!("Step {idx}: ");
print_for_debug(&code, i);
print_for_debug(&code);
} else {
print!("Halted")
},
"p" | "print" => print_for_debug(&code, i),
"d" | "dump" => print!("Rules: {}", premacro.repo.bundle(i)),
"p" | "print" => print_for_debug(&code),
"d" | "dump" => print!("Rules: {}", premacro.repo),
"q" | "quit" => return,
"h" | "help" => print!(
"Available commands:
Expand Down Expand Up @@ -146,22 +143,22 @@ pub fn main() {
.add_system(StlConfig { impure: true })
.add_system(asynch)
.add_system(io);
let premacro = i.unwrap(env.load_dir(&dir, &main));
let premacro = env.load_dir(&dir, &main).unwrap();
if args.dump_repo {
println!("Parsed rules: {}", premacro.repo.bundle(&i));
println!("Parsed rules: {}", premacro.repo);
return;
}
if !args.macro_debug.is_empty() {
let sym = i.i(&to_vname(&args.macro_debug, &i));
return macro_debug(premacro, sym, &i);
return macro_debug(premacro, sym);
}
let mut proc = i.unwrap(premacro.build_process(Some(args.macro_limit)));
let mut proc = premacro.build_process(Some(args.macro_limit)).unwrap();
let main = interpreted::Clause::Constant(i.i(&main)).wrap();
let ret = i.unwrap(proc.run(main, None));
let ret = proc.run(main, None).unwrap();
let interpreter::Return { gas, state, inert } = ret;
drop(proc);
if inert {
println!("Settled at {}", state.expr().clause.bundle(&i));
println!("Settled at {}", state.expr().clause);
if let Some(g) = gas {
println!("Remaining gas: {g}")
}
Expand Down
10 changes: 6 additions & 4 deletions src/error/import_all.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::rc::Rc;

use itertools::Itertools;

use super::ProjectError;
use crate::representations::location::Location;
use crate::{Interner, VName};
use crate::VName;

/// Error produced for the statement `import *`
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Expand All @@ -16,11 +18,11 @@ impl ProjectError for ImportAll {
fn description(&self) -> &str {
"a top-level glob import was used"
}
fn message(&self, i: &Interner) -> String {
format!("{} imports *", i.extern_all(&self.offender_mod).join("::"))
fn message(&self) -> String {
format!("{} imports *", self.offender_mod.iter().join("::"))
}

fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
Location::File(self.offender_file.clone())
}
}
3 changes: 1 addition & 2 deletions src/error/no_targets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use super::{ErrorPosition, ProjectError};
use crate::parse_layer;
use crate::utils::iter::box_empty;
use crate::utils::BoxedIter;
use crate::Interner;

/// Error produced when [parse_layer] is called without targets. This function
/// produces an error instead of returning a straightforward empty tree because
Expand All @@ -17,7 +16,7 @@ impl ProjectError for NoTargets {
"No targets were specified for layer parsing"
}

fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
box_empty()
}
}
12 changes: 7 additions & 5 deletions src/error/not_exported.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,23 @@ impl ProjectError for NotExported {
fn description(&self) -> &str {
"An import refers to a symbol that exists but isn't exported"
}
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
fn positions(&self) -> BoxedIter<ErrorPosition> {
Box::new(
[
ErrorPosition {
location: Location::File(Rc::new(i.extern_all(&self.file))),
location: Location::File(Rc::new(Interner::extern_all(&self.file))),
message: Some(format!(
"{} isn't exported",
i.extern_all(&self.subpath).join("::")
Interner::extern_all(&self.subpath).join("::")
)),
},
ErrorPosition {
location: Location::File(Rc::new(i.extern_all(&self.referrer_file))),
location: Location::File(Rc::new(Interner::extern_all(
&self.referrer_file,
))),
message: Some(format!(
"{} cannot see this symbol",
i.extern_all(&self.referrer_subpath).join("::")
Interner::extern_all(&self.referrer_subpath).join("::")
)),
},
]
Expand Down
12 changes: 6 additions & 6 deletions src/error/not_found.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl NotFound {
) -> Self {
let last_mod =
orig.walk_ref(&path[..e.pos], false).expect("error occured on next step");
let mut whole_path = prefix.iter().chain(path.iter()).copied();
let mut whole_path = prefix.iter().chain(path.iter()).cloned();
if let Some(file) = &last_mod.extra.file {
Self {
source: Some(source.to_vec()),
Expand All @@ -57,14 +57,14 @@ impl ProjectError for NotFound {
fn description(&self) -> &str {
"an import refers to a nonexistent module"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"module {} in {} was not found",
i.extern_all(&self.subpath).join("::"),
i.extern_all(&self.file).join("/"),
Interner::extern_all(&self.subpath).join("::"),
Interner::extern_all(&self.file).join("/"),
)
}
fn one_position(&self, i: &Interner) -> crate::Location {
Location::File(Rc::new(i.extern_all(&self.file)))
fn one_position(&self) -> crate::Location {
Location::File(Rc::new(Interner::extern_all(&self.file)))
}
}
12 changes: 5 additions & 7 deletions src/error/parse_error_with_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ use std::rc::Rc;
use itertools::Itertools;

use super::{ErrorPosition, ProjectError};
use crate::interner::InternedDisplay;
use crate::parse::Entry;
use crate::utils::BoxedIter;
use crate::Interner;

/// Produced by stages that parse text when it fails.
pub struct ParseErrorWithTokens {
Expand All @@ -21,14 +19,14 @@ impl ProjectError for ParseErrorWithTokens {
fn description(&self) -> &str {
self.error.description()
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"Failed to parse code: {}\nTokenized source for context:\n{}",
self.error.message(i),
self.tokens.iter().map(|t| t.to_string_i(i)).join(" "),
self.error.message(),
self.tokens.iter().map(|t| t.to_string()).join(" "),
)
}
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
self.error.positions(i)
fn positions(&self) -> BoxedIter<ErrorPosition> {
self.error.positions()
}
}
30 changes: 16 additions & 14 deletions src/error/project_error.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::fmt::Debug;
use std::fmt::Display;
use std::rc::Rc;

use crate::interner::InternedDisplay;
use crate::representations::location::Location;
use crate::utils::iter::box_once;
use crate::utils::BoxedIter;
use crate::Interner;

/// A point of interest in resolving the error, such as the point where
/// processing got stuck, a command that is likely to be incorrect
Expand All @@ -21,17 +21,17 @@ pub trait ProjectError {
/// A general description of this type of error
fn description(&self) -> &str;
/// A formatted message that includes specific parameters
fn message(&self, _i: &Interner) -> String {
fn message(&self) -> String {
self.description().to_string()
}
/// Code positions relevant to this error. If you don't implement this, you
/// must implement [ProjectError::one_position]
fn positions(&self, i: &Interner) -> BoxedIter<ErrorPosition> {
box_once(ErrorPosition { location: self.one_position(i), message: None })
fn positions(&self) -> BoxedIter<ErrorPosition> {
box_once(ErrorPosition { location: self.one_position(), message: None })
}
/// Short way to provide a single location. If you don't implement this, you
/// must implement [ProjectError::positions]
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
unimplemented!()
}
/// Convert the error into an `Rc<dyn ProjectError>` to be able to
Expand All @@ -44,15 +44,11 @@ pub trait ProjectError {
}
}

impl InternedDisplay for dyn ProjectError {
fn fmt_i(
&self,
f: &mut std::fmt::Formatter<'_>,
i: &Interner,
) -> std::fmt::Result {
impl Display for dyn ProjectError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let description = self.description();
let message = self.message(i);
let positions = self.positions(i);
let message = self.message();
let positions = self.positions();
writeln!(f, "Project error: {description}\n{message}")?;
for ErrorPosition { location, message } in positions {
writeln!(
Expand All @@ -65,6 +61,12 @@ impl InternedDisplay for dyn ProjectError {
}
}

impl Debug for dyn ProjectError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self}")
}
}

/// Alias for a result with an error of [Rc] of [ProjectError] trait object.
/// This is the type of result most commonly returned by pre-run operations.
pub type ProjectResult<T> = Result<T, Rc<dyn ProjectError>>;
10 changes: 5 additions & 5 deletions src/error/too_many_supers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ impl ProjectError for TooManySupers {
"an import path starts with more `super` segments than the current \
module's absolute path"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"path {} in {} contains too many `super` steps.",
i.extern_all(&self.path).join("::"),
i.extern_all(&self.offender_mod).join("::")
Interner::extern_all(&self.path).join("::"),
Interner::extern_all(&self.offender_mod).join("::")
)
}

fn one_position(&self, i: &Interner) -> Location {
Location::File(Rc::new(i.extern_all(&self.offender_file)))
fn one_position(&self) -> Location {
Location::File(Rc::new(Interner::extern_all(&self.offender_file)))
}
}
8 changes: 4 additions & 4 deletions src/error/unexpected_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ impl ProjectError for UnexpectedDirectory {
"A stage that deals specifically with code encountered a path that refers \
to a directory"
}
fn one_position(&self, i: &Interner) -> crate::Location {
Location::File(Rc::new(i.extern_all(&self.path)))
fn one_position(&self) -> crate::Location {
Location::File(Rc::new(Interner::extern_all(&self.path)))
}

fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"{} was expected to be a file but a directory was found",
i.extern_all(&self.path).join("/")
Interner::extern_all(&self.path).join("/")
)
}
}
6 changes: 3 additions & 3 deletions src/error/visibility_mismatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ impl ProjectError for VisibilityMismatch {
fn description(&self) -> &str {
"Some occurences of a namespace are exported but others are not"
}
fn message(&self, i: &Interner) -> String {
fn message(&self) -> String {
format!(
"{} is opened multiple times with different visibilities",
i.extern_all(&self.namespace).join("::")
Interner::extern_all(&self.namespace).join("::")
)
}
fn one_position(&self, _i: &Interner) -> Location {
fn one_position(&self) -> Location {
Location::File(self.file.clone())
}
}
2 changes: 1 addition & 1 deletion src/facade/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl<'a> Environment<'a> {
) -> ProjectResult<PreMacro<'a>> {
let i = self.i;
let CompiledEnv { prelude, systems, tree } = self.compile()?;
let file_cache = file_loader::mk_dir_cache(dir.to_path_buf(), i);
let file_cache = file_loader::mk_dir_cache(dir.to_path_buf());
let vname_tree = parse_layer(
iter::once(target),
&|path| file_cache.find(path),
Expand Down
Loading

0 comments on commit 0b887ce

Please sign in to comment.