forked from Orchid/orchid
removed dead files
This commit is contained in:
@@ -1,67 +0,0 @@
|
|||||||
//! Errors produced by the interpreter
|
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use dyn_clone::DynClone;
|
|
||||||
|
|
||||||
use crate::error::ProjectErrorObj;
|
|
||||||
use crate::location::CodeLocation;
|
|
||||||
|
|
||||||
/// Errors produced by external code when runtime-enforced assertions are
|
|
||||||
/// violated.
|
|
||||||
pub trait RTError: fmt::Display + Send + Sync + DynClone {
|
|
||||||
/// Convert into trait object
|
|
||||||
#[must_use]
|
|
||||||
fn pack(self) -> RTErrorObj
|
|
||||||
where Self: 'static + Sized {
|
|
||||||
Arc::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for dyn RTError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ExternError({self})") }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for dyn RTError {}
|
|
||||||
|
|
||||||
impl RTError for ProjectErrorObj {}
|
|
||||||
|
|
||||||
/// An error produced by Rust code called form Orchid. The error is type-erased.
|
|
||||||
pub type RTErrorObj = Arc<dyn RTError>;
|
|
||||||
|
|
||||||
/// A result produced by Rust code called from Orchid.
|
|
||||||
pub type RTResult<T> = Result<T, RTErrorObj>;
|
|
||||||
|
|
||||||
/// Some expectation (usually about the argument types of a function) did not
|
|
||||||
/// hold.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct AssertionError {
|
|
||||||
location: CodeLocation,
|
|
||||||
message: &'static str,
|
|
||||||
details: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AssertionError {
|
|
||||||
/// Construct, upcast and wrap in a Result that never succeeds for easy
|
|
||||||
/// short-circuiting
|
|
||||||
pub fn fail<T>(location: CodeLocation, message: &'static str, details: String) -> RTResult<T> {
|
|
||||||
Err(Self::ext(location, message, details))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct and upcast to [RTErrorObj]
|
|
||||||
pub fn ext(location: CodeLocation, message: &'static str, details: String) -> RTErrorObj {
|
|
||||||
Self { location, message, details }.pack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for AssertionError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Error: expected {}", self.message)?;
|
|
||||||
write!(f, " at {}", self.location)?;
|
|
||||||
write!(f, " details: {}", self.details)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RTError for AssertionError {}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
//! Addiitional information passed to the interpreter
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
|
|
||||||
use super::handler::HandlerTable;
|
|
||||||
use super::nort::{Clause, Expr};
|
|
||||||
use crate::foreign::error::{RTError, RTErrorObj, RTResult};
|
|
||||||
use crate::location::CodeLocation;
|
|
||||||
use crate::name::Sym;
|
|
||||||
|
|
||||||
/// Data that must not change except in well-defined ways while any data
|
|
||||||
/// associated with this process persists
|
|
||||||
pub struct RunEnv<'a> {
|
|
||||||
/// Mutable callbacks the code can invoke with continuation passing
|
|
||||||
pub handlers: HandlerTable<'a>,
|
|
||||||
/// Constants referenced in the code in [super::nort::Clause::Constant] nodes
|
|
||||||
pub symbols: RefCell<HashMap<Sym, RTResult<Expr>>>,
|
|
||||||
/// Callback to invoke when a symbol is not found
|
|
||||||
pub symbol_cb: Box<dyn Fn(Sym, CodeLocation) -> RTResult<Expr> + 'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> RunEnv<'a> {
|
|
||||||
/// Create a new context. The return values of the symbol callback are cached
|
|
||||||
pub fn new(
|
|
||||||
handlers: HandlerTable<'a>,
|
|
||||||
symbol_cb: impl Fn(Sym, CodeLocation) -> RTResult<Expr> + 'a,
|
|
||||||
) -> Self {
|
|
||||||
Self { handlers, symbols: RefCell::new(HashMap::new()), symbol_cb: Box::new(symbol_cb) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Produce an error indicating that a symbol was missing
|
|
||||||
pub fn sym_not_found(sym: Sym, location: CodeLocation) -> RTErrorObj {
|
|
||||||
MissingSymbol { location, sym }.pack()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load a symbol from cache or invoke the callback
|
|
||||||
pub fn load(&self, sym: Sym, location: CodeLocation) -> RTResult<Expr> {
|
|
||||||
let mut guard = self.symbols.borrow_mut();
|
|
||||||
let (_, r) = (guard.raw_entry_mut().from_key(&sym))
|
|
||||||
.or_insert_with(|| (sym.clone(), (self.symbol_cb)(sym, location)));
|
|
||||||
r.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to resolve the command with the command handler table
|
|
||||||
pub fn dispatch(&self, expr: &Clause, location: CodeLocation) -> Option<Expr> {
|
|
||||||
match expr {
|
|
||||||
Clause::Atom(at) => self.handlers.dispatch(&*at.0, location),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Limits and other context that is subject to change
|
|
||||||
pub struct RunParams {
|
|
||||||
/// Number of reduction steps permitted before the program is preempted
|
|
||||||
pub gas: Option<usize>,
|
|
||||||
/// Maximum recursion depth. Orchid uses a soft stack so this can be very
|
|
||||||
/// large, but it must not be
|
|
||||||
pub stack: usize,
|
|
||||||
}
|
|
||||||
impl RunParams {
|
|
||||||
/// Consume some gas if it is being counted
|
|
||||||
pub fn use_gas(&mut self, amount: usize) {
|
|
||||||
if let Some(g) = self.gas.as_mut() {
|
|
||||||
*g = g.saturating_sub(amount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Gas is being counted and there is none left
|
|
||||||
pub fn no_gas(&self) -> bool { self.gas == Some(0) }
|
|
||||||
/// Add gas to make execution longer, or to resume execution in a preempted
|
|
||||||
/// expression
|
|
||||||
pub fn add_gas(&mut self, amount: usize) {
|
|
||||||
if let Some(g) = self.gas.as_mut() {
|
|
||||||
*g = g.saturating_add(amount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The interpreter's sole output excluding error conditions is an expression
|
|
||||||
pub type Halt = Expr;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(crate) struct MissingSymbol {
|
|
||||||
pub sym: Sym,
|
|
||||||
pub location: CodeLocation,
|
|
||||||
}
|
|
||||||
impl RTError for MissingSymbol {}
|
|
||||||
impl fmt::Display for MissingSymbol {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}, called at {} is not loaded", self.sym, self.location)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
//! Unified extension struct instances of which are catalogued by
|
|
||||||
//! [super::loader::Loader]. Language extensions must implement [IntoSystem].
|
|
||||||
|
|
||||||
use crate::error::{ErrorPosition, ProjectError};
|
|
||||||
use crate::gen::tree::ConstTree;
|
|
||||||
use crate::interpreter::handler::HandlerTable;
|
|
||||||
use crate::name::VName;
|
|
||||||
use crate::parse::lex_plugin::LexerPlugin;
|
|
||||||
use crate::parse::parse_plugin::ParseLinePlugin;
|
|
||||||
use crate::pipeline::load_project::Prelude;
|
|
||||||
use crate::virt_fs::DeclTree;
|
|
||||||
|
|
||||||
/// A description of every point where an external library can hook into Orchid.
|
|
||||||
/// Intuitively, this can be thought of as a plugin
|
|
||||||
pub struct System<'a> {
|
|
||||||
/// An identifier for the system used eg. in error reporting.
|
|
||||||
pub name: &'a str,
|
|
||||||
/// External functions and other constant values defined in AST form
|
|
||||||
pub constants: ConstTree,
|
|
||||||
/// Orchid libraries defined by this system
|
|
||||||
pub code: DeclTree,
|
|
||||||
/// Prelude lines to be added to the head of files to expose the
|
|
||||||
/// functionality of this system. A glob import from the first path is
|
|
||||||
/// added to every file outside the prefix specified by the second path
|
|
||||||
pub prelude: Vec<Prelude>,
|
|
||||||
/// Handlers for actions defined in this system
|
|
||||||
pub handlers: HandlerTable<'a>,
|
|
||||||
/// Custom lexer for the source code representation atomic data.
|
|
||||||
/// These take priority over builtin lexers so the syntax they
|
|
||||||
/// match should be unambiguous
|
|
||||||
pub lexer_plugins: Vec<Box<dyn LexerPlugin + 'a>>,
|
|
||||||
/// Parser that processes custom line types into their representation in the
|
|
||||||
/// module tree
|
|
||||||
pub line_parsers: Vec<Box<dyn ParseLinePlugin>>,
|
|
||||||
}
|
|
||||||
impl<'a> System<'a> {
|
|
||||||
/// Intern the name of the system so that it can be used as an Orchid
|
|
||||||
/// namespace
|
|
||||||
#[must_use]
|
|
||||||
pub fn vname(&self) -> VName {
|
|
||||||
VName::parse(self.name).expect("Systems must have a non-empty name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error raised when a system fails to load a path. This usually means that
|
|
||||||
/// another system the current one depends on did not get loaded
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct MissingSystemCode {
|
|
||||||
path: VName,
|
|
||||||
system: Vec<String>,
|
|
||||||
referrer: VName,
|
|
||||||
}
|
|
||||||
impl ProjectError for MissingSystemCode {
|
|
||||||
const DESCRIPTION: &'static str = "A system tried to import a path that doesn't exist";
|
|
||||||
fn message(&self) -> String {
|
|
||||||
format!(
|
|
||||||
"Path {} imported by {} is not defined by {} or any system before it",
|
|
||||||
self.path,
|
|
||||||
self.referrer,
|
|
||||||
self.system.join("::")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
fn positions(&self) -> impl IntoIterator<Item = ErrorPosition> { [] }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait for objects that can be converted into a [System].
|
|
||||||
pub trait IntoSystem<'a> {
|
|
||||||
/// Convert this object into a system using an interner
|
|
||||||
fn into_system(self) -> System<'a>;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
//! Conversions from Orchid expressions to Rust values. Many APIs and
|
|
||||||
//! [super::fn_bridge] in particular use this to automatically convert values on
|
|
||||||
//! the boundary. Failures cause an interpreter exit
|
|
||||||
|
|
||||||
use super::error::RTResult;
|
|
||||||
use crate::interpreter::nort::{ClauseInst, Expr};
|
|
||||||
use crate::location::CodeLocation;
|
|
||||||
|
|
||||||
/// Types automatically convertible from an [Expr]. Most notably, this is how
|
|
||||||
/// foreign functions request automatic argument downcasting.
|
|
||||||
pub trait TryFromExpr: Sized {
|
|
||||||
/// Match and clone the value out of an [Expr]
|
|
||||||
fn from_expr(expr: Expr) -> RTResult<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFromExpr for Expr {
|
|
||||||
fn from_expr(expr: Expr) -> RTResult<Self> { Ok(expr) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFromExpr for ClauseInst {
|
|
||||||
fn from_expr(expr: Expr) -> RTResult<Self> { Ok(expr.clsi()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Request a value of a particular type and also return its location for
|
|
||||||
/// further error reporting
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct WithLoc<T>(pub CodeLocation, pub T);
|
|
||||||
impl<T: TryFromExpr> TryFromExpr for WithLoc<T> {
|
|
||||||
fn from_expr(expr: Expr) -> RTResult<Self> { Ok(Self(expr.location(), T::from_expr(expr)?)) }
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user