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:
@@ -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}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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("::")
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>>;
|
||||||
|
|||||||
@@ -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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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("/")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|||||||
@@ -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()) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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("::")
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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()?;
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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| {
|
||||||
|
|||||||
@@ -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)| {
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
@@ -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![],
|
||||||
|
|||||||
@@ -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)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()) },
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
|||||||
@@ -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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)) => {
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, "]")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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
61
src/systems/stl/state.rs
Normal 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)),
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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("::")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user