rustre_core/engine/
world.rsuse crate::engine::FileError;
use comemo::Prehashed;
use ecow::{EcoString, EcoVec};
use rustre_parser::ast::Root;
use rustre_parser::ParserError;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::path::Path;
use std::rc::Rc;
#[track]
pub trait World {
fn input_files(&self) -> EcoVec<Source>;
fn imported_file(&self, relative_to: &Source, path: &Path) -> Result<Source, FileError>;
}
#[derive(Clone, Eq, Hash, PartialEq)]
pub struct FileId(Prehashed<FileIdInner>);
#[derive(Clone, Eq, Hash, PartialEq)]
enum FileIdInner {
Normal(Rc<Path>),
StdLib,
}
impl Debug for FileId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_stdlib() {
write!(f, "<standard library>")
} else {
self.path().fmt(f)
}
}
}
impl FileId {
#[track_caller]
pub fn new(path: impl AsRef<Path>) -> Self {
Self(Prehashed::new(FileIdInner::Normal(
path.as_ref().to_owned().into(),
)))
}
pub fn stdlib() -> Self {
Self(Prehashed::new(FileIdInner::StdLib))
}
pub fn is_stdlib(&self) -> bool {
matches!(&*self.0, FileIdInner::StdLib)
}
pub fn path(&self) -> &Path {
if let FileIdInner::Normal(ref path) = &*self.0 {
path
} else {
Path::new("/@stdlib.lus")
}
}
}
#[derive(Clone)]
pub struct Source(Rc<SourceImpl>);
impl Eq for Source {}
impl PartialEq for Source {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
}
impl Hash for Source {
fn hash<H: Hasher>(&self, state: &mut H) {
std::ptr::hash(Rc::as_ptr(&self.0), state);
}
}
struct SourceImpl {
id: FileId,
raw: Prehashed<EcoString>,
syntax: Prehashed<Root>,
syntax_errors: EcoVec<ParserError>,
}
impl Debug for Source {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Source")
.field("id", &self.0.id)
.finish_non_exhaustive()
}
}
impl Hash for SourceImpl {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.raw.hash(state);
self.syntax.hash(state);
}
}
impl AsRef<str> for Source {
fn as_ref(&self) -> &str {
self.0.raw.as_str()
}
}
impl AsRef<[u8]> for Source {
fn as_ref(&self) -> &[u8] {
self.0.raw.as_bytes()
}
}
impl Source {
pub fn new(id: FileId, text: String) -> Self {
let (root, syntax_errors) = rustre_parser::parse(&text);
Self(Rc::new(SourceImpl {
id,
raw: Prehashed::new(text.into()),
syntax: Prehashed::new(root),
syntax_errors: syntax_errors.into(),
}))
}
pub fn stdlib() -> Self {
Source::new(FileId::stdlib(), include_str!("../stdlib.lus").into())
}
pub fn file(&self) -> FileId {
self.0.id.clone()
}
pub fn root(&self) -> Root {
self.0.syntax.clone().into_inner()
}
pub fn syntax_errors(&self) -> EcoVec<ParserError> {
self.0.syntax_errors.clone()
}
}