Fixed a tricky type erasure bug in the scheduler

This commit is contained in:
2023-10-12 14:36:59 +01:00
parent af3e9f67fa
commit cb395da894
32 changed files with 147 additions and 125 deletions

7
examples/y/main.orc Normal file
View File

@@ -0,0 +1,7 @@
import system::async::(set_timer, yield)
import system::io::(readln, println)
const main := (
set_timer true 1 (println "y" yield)
\cancel. readln \a. cancel
)

View File

@@ -1,24 +1,24 @@
//! Various errors the pipeline can produce
mod assertion_error;
mod conflicting_roles;
mod import_all;
mod no_targets;
mod not_exported;
mod parse_error_with_tokens;
mod project_error;
mod runtime_error;
mod too_many_supers;
mod unexpected_directory;
mod visibility_mismatch;
mod assertion_error;
mod runtime_error;
pub use assertion_error::AssertionError;
pub use conflicting_roles::ConflictingRoles;
pub use import_all::ImportAll;
pub use no_targets::NoTargets;
pub use not_exported::NotExported;
pub use parse_error_with_tokens::ParseErrorWithTokens;
pub use project_error::{ErrorPosition, ProjectError, ProjectResult};
pub use runtime_error::RuntimeError;
pub use too_many_supers::TooManySupers;
pub use unexpected_directory::UnexpectedDirectory;
pub use visibility_mismatch::VisibilityMismatch;
pub use assertion_error::AssertionError;
pub use runtime_error::RuntimeError;

View File

@@ -37,8 +37,7 @@ pub trait StrictEq {
}
/// Functionality the interpreter needs to handle a value
pub trait Atomic:
Any + Debug + DynClone + StrictEq + Responder + Send
pub trait Atomic: Any + Debug + DynClone + StrictEq + Responder + Send
where
Self: 'static,
{

View File

@@ -3,7 +3,7 @@ use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::rc::Rc;
use dyn_clone::{DynClone, clone_box};
use dyn_clone::{clone_box, DynClone};
use super::XfnResult;
use crate::interpreted::ExprInst;
@@ -81,7 +81,5 @@ impl ExFn {
}
}
impl Clone for ExFn {
fn clone(&self) -> Self {
Self(clone_box(self.0.as_ref()))
}
fn clone(&self) -> Self { Self(clone_box(self.0.as_ref())) }
}

View File

@@ -11,7 +11,7 @@ mod inert;
use std::rc::Rc;
pub use atom::{Atom, Atomic, AtomicResult, AtomicReturn, StrictEq};
pub use extern_fn::{ExternError, ExternFn, ExFn};
pub use extern_fn::{ExFn, ExternError, ExternFn};
pub use fn_bridge::constructors::{
xfn_1ary, xfn_2ary, xfn_3ary, xfn_4ary, xfn_5ary, xfn_6ary, xfn_7ary,
xfn_8ary, xfn_9ary,

View File

@@ -1,6 +1,6 @@
use std::borrow::Borrow;
use std::hash::{BuildHasher, Hash};
use std::sync::{RwLock, Arc};
use std::sync::{Arc, RwLock};
use hashbrown::HashMap;

View File

@@ -70,14 +70,12 @@ pub fn run_handler(
loop {
let mut ret = run(expr, ctx.clone())?;
let quit = take_with_output(&mut ret.state, |exi| match exi.expr_val() {
Expr { clause: Clause::Atom(a), .. } => {
match handlers.dispatch(a.0) {
Expr { clause: Clause::Atom(a), .. } => match handlers.dispatch(a.0) {
Err(b) => (Clause::Atom(Atom(b)).wrap(), Ok(true)),
Ok(e) => match e {
Ok(expr) => (expr, Ok(false)),
Err(e) => (Clause::Bottom.wrap(), Err(e)),
},
}
},
expr => (ExprInst::new(expr), Ok(true)),
})?;

View File

@@ -183,7 +183,9 @@ impl ProjectError for NaNLiteral {
pub struct LiteralOverflow(pub Location);
impl ProjectError for LiteralOverflow {
fn description(&self) -> &str { "number literal described number greater than usize::MAX" }
fn description(&self) -> &str {
"number literal described number greater than usize::MAX"
}
fn one_position(&self) -> Location { self.0.clone() }
}

View File

@@ -11,7 +11,12 @@ pub fn parse2(ctx: impl Context) -> ProjectResult<Vec<FileEntry>> {
Ok(Vec::new())
} else {
parse_module_body(Stream::from_slice(&tokens), &ctx).map_err(|error| {
ParseErrorWithTokens { error, full_source: ctx.source().to_string(), tokens }.rc()
ParseErrorWithTokens {
error,
full_source: ctx.source().to_string(),
tokens,
}
.rc()
})
}
}

View File

@@ -5,15 +5,15 @@ use std::sync::Arc;
use itertools::Itertools;
use ordered_float::NotNan;
use super::LexerPlugin;
use super::context::Context;
use super::errors::{FloatPlacehPrio, NoCommentEnd};
use super::numeric::{parse_num, print_nat16, numstart};
use super::numeric::{numstart, parse_num, print_nat16};
use super::LexerPlugin;
use crate::ast::{PHClass, Placeholder};
use crate::error::{ProjectResult, ProjectError};
use crate::error::{ProjectError, ProjectResult};
use crate::foreign::Atom;
use crate::interner::Tok;
use crate::parse::numeric::{numchar, lex_numeric};
use crate::parse::numeric::{lex_numeric, numchar};
use crate::parse::string::lex_string;
use crate::systems::stl::Numeric;
use crate::utils::pure_seq::next;
@@ -210,7 +210,7 @@ pub fn lex(
ctx: &impl Context,
) -> ProjectResult<Vec<Entry>> {
let mut prev_len = data.len() + 1;
'tail:loop {
'tail: loop {
if prev_len == data.len() {
panic!("got stuck at {data:?}, parsed {:?}", tokens.last().unwrap());
}
@@ -234,7 +234,8 @@ pub fn lex(
}
for (prefix, lexeme) in lit_table() {
if let Some(tail) = data.strip_prefix(prefix) {
tokens.push(Entry::new(ctx.location(prefix.len(), tail), lexeme.clone()));
tokens
.push(Entry::new(ctx.location(prefix.len(), tail), lexeme.clone()));
data = tail;
continue 'tail;
}
@@ -267,7 +268,11 @@ pub fn lex(
if tail.chars().next().map_or(false, numstart) {
let (num, post_num) = split_filter(tail, numchar);
if let Some(tail) = post_num.strip_prefix("=>") {
let lexeme = Lexeme::Arrow(parse_num(num).map_err(|e| e.into_proj(num.len(), post_num, ctx))?.as_float());
let lexeme = Lexeme::Arrow(
parse_num(num)
.map_err(|e| e.into_proj(num.len(), post_num, ctx))?
.as_float(),
);
let location = ctx.location(num.len() + 3, tail);
tokens.push(Entry::new(location, lexeme));
data = tail;
@@ -281,7 +286,8 @@ pub fn lex(
if !name.is_empty() {
let name = ctx.interner().i(name);
let location = ctx.location(name.len() + 1, tail);
let lexeme = Lexeme::Placeh(Placeholder { name, class: PHClass::Scalar });
let lexeme =
Lexeme::Placeh(Placeholder { name, class: PHClass::Scalar });
tokens.push(Entry::new(location, lexeme));
data = tail;
continue 'tail;
@@ -302,7 +308,8 @@ pub fn lex(
.map_err(|e| e.into_proj(num_str.len(), tail, ctx))
.and_then(|num| {
Ok(unwrap_or!(num => Numeric::Uint; {
return Err(FloatPlacehPrio(ctx.location(num_str.len(), tail)).rc())
let location = ctx.location(num_str.len(), tail);
return Err(FloatPlacehPrio(location).rc())
}))
})
.map(|p| (p, num_str.len() + 1, tail))

View File

@@ -8,7 +8,7 @@ mod sourcefile;
mod stream;
mod string;
pub use context::{ParsingContext, Context, LexerPlugin, LineParser};
pub use context::{Context, LexerPlugin, LineParser, ParsingContext};
pub use facade::parse2;
pub use lexer::{namechar, namestart, opchar, split_filter, Entry, Lexeme};
pub use numeric::{

View File

@@ -143,14 +143,14 @@ mod test {
#[must_use]
pub fn print_nat16(num: NotNan<f64>) -> String {
if *num == 0.0 {
return "0x0".to_string()
return "0x0".to_string();
} else if num.is_infinite() {
return match num.is_sign_positive() {
true => "Infinity".to_string(),
false => "-Infinity".to_string(),
}
};
} else if num.is_nan() {
return "NaN".to_string()
return "NaN".to_string();
}
let exp = num.log(16.0).floor();
let man = *num / 16_f64.powf(exp);

View File

@@ -111,7 +111,10 @@ mod test {
let (data, tail) = lex_string(source, &MockContext(&i))
.expect("the snippet starts with a quote")
.expect("it contains a valid string");
assert_eq!(data.try_downcast::<OrcString>().unwrap().as_str(), "hello world!");
assert_eq!(
data.try_downcast::<OrcString>().unwrap().as_str(),
"hello world!"
);
assert_eq!(tail, " - says the programmer");
}
}

View File

@@ -5,7 +5,7 @@ use crate::sourcefile::FileEntry;
#[derive(Debug)]
pub struct LoadedSource {
pub entries: Vec<FileEntry>
pub entries: Vec<FileEntry>,
}
pub type LoadedSourceTable = HashMap<VName, LoadedSource>;

View File

@@ -5,7 +5,7 @@
use std::fmt::{Debug, Display};
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use std::sync::{Arc, TryLockError, Mutex};
use std::sync::{Arc, Mutex, TryLockError};
#[allow(unused)] // for doc
use super::ast;

View File

@@ -2,7 +2,7 @@ use std::fmt::{Debug, Write};
use std::rc::Rc;
use super::location::Location;
use crate::foreign::{ExFn, Atom};
use crate::foreign::{Atom, ExFn};
use crate::utils::string_from_charset;
use crate::Sym;

View File

@@ -19,10 +19,9 @@ fn collect_paths_cls_rec(
match cls {
postmacro::Clause::Atom(_) | postmacro::Clause::ExternFn(_) => None,
postmacro::Clause::Constant(_) => None,
postmacro::Clause::LambdaArg(h) =>
match *h != depth {
postmacro::Clause::LambdaArg(h) => match *h != depth {
true => None,
false => Some(PathSet::pick())
false => Some(PathSet::pick()),
},
postmacro::Clause::Lambda(b) => collect_paths_expr_rec(b, depth + 1),
postmacro::Clause::Apply(f, x) => {
@@ -43,7 +42,8 @@ pub fn clause(cls: &postmacro::Clause) -> interpreted::Clause {
postmacro::Clause::Constant(name) =>
interpreted::Clause::Constant(name.clone()),
postmacro::Clause::Atom(a) => interpreted::Clause::Atom(a.clone()),
postmacro::Clause::ExternFn(fun) => interpreted::Clause::ExternFn(fun.clone()),
postmacro::Clause::ExternFn(fun) =>
interpreted::Clause::ExternFn(fun.clone()),
postmacro::Clause::Apply(f, x) =>
interpreted::Clause::Apply { f: expr(f.as_ref()), x: expr(x.as_ref()) },
postmacro::Clause::Lambda(body) => interpreted::Clause::Lambda {

View File

@@ -11,8 +11,8 @@ use super::state::apply_exprv;
use super::{update_first_seq, RuleError, VectreeMatcher};
use crate::ast::Rule;
use crate::interner::Interner;
use crate::Sym;
use crate::parse::print_nat16;
use crate::Sym;
#[derive(Debug)]
pub struct CachedRule<M: Matcher> {

View File

@@ -51,8 +51,9 @@ impl Display for RuleError {
Self::Multiple(key) => {
write!(f, "Key {key} appears multiple times in match pattern")
},
Self::VecNeighbors(left, right) =>
write!(f, "vectorials {left} and {right} are next to each other"),
Self::VecNeighbors(left, right) => {
write!(f, "vectorials {left} and {right} are next to each other")
},
}
}
}

View File

@@ -27,8 +27,9 @@ pub fn apply_exprv(template: &[RuleExpr], state: &State) -> Vec<RuleExpr> {
pub fn apply_expr(template: &RuleExpr, state: &State) -> Vec<RuleExpr> {
let Expr { location, value } = template;
match value {
Clause::Atom(_) | Clause::Name(_) | Clause::ExternFn(_) =>
vec![template.clone()],
Clause::Atom(_) | Clause::Name(_) | Clause::ExternFn(_) => {
vec![template.clone()]
},
Clause::S(c, body) => vec![Expr {
location: location.clone(),
value: Clause::S(*c, Rc::new(apply_exprv(body.as_slice(), state))),

View File

@@ -18,6 +18,7 @@ use crate::interpreted::{Clause, ExprInst};
use crate::interpreter::HandlerTable;
use crate::pipeline::file_loader::embed_to_map;
use crate::systems::codegen::call;
use crate::systems::stl::Numeric;
use crate::utils::poller::{PollEvent, Poller};
use crate::utils::unwrap_or;
use crate::{ConstTree, Interner};
@@ -28,8 +29,8 @@ struct Timer {
delay: NotNan<f64>,
}
pub fn set_timer(recurring: bool, delay: NotNan<f64>) -> XfnResult<Clause> {
Ok(init_cps(2, Timer { recurring, delay }))
pub fn set_timer(recurring: bool, delay: Numeric) -> XfnResult<Clause> {
Ok(init_cps(2, Timer { recurring, delay: delay.as_float() }))
}
#[derive(Clone)]
@@ -38,9 +39,7 @@ impl CancelTimer {
pub fn new(f: impl Fn() + Send + 'static) -> Self {
Self(Arc::new(Mutex::new(f)))
}
pub fn cancel(&self) {
self.0.lock().unwrap()()
}
pub fn cancel(&self) { self.0.lock().unwrap()() }
}
impl Debug for CancelTimer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@@ -39,7 +39,8 @@ pub fn tuple(data: impl IntoIterator<Item = ExprInst>) -> Clause {
#[cfg(test)]
mod test {
use crate::{systems::codegen::tuple, foreign::Atomic};
use crate::foreign::Atomic;
use crate::systems::codegen::tuple;
#[test]
fn tuple_printer() {

View File

@@ -2,12 +2,12 @@ use super::flow::IOCmdHandlePack;
use super::instances::{BRead, ReadCmd, SRead, Sink, Source, WriteCmd};
use crate::error::RuntimeError;
use crate::foreign::cps_box::init_cps;
use crate::foreign::{xfn_1ary, xfn_2ary, Atomic, XfnResult, Atom};
use crate::foreign::{xfn_1ary, xfn_2ary, Atom, Atomic, XfnResult};
use crate::interpreted::Clause;
use crate::representations::OrcString;
use crate::systems::scheduler::SharedHandle;
use crate::systems::stl::Binary;
use crate::{ConstTree, Interner, ast};
use crate::{ast, ConstTree, Interner};
type WriteHandle = SharedHandle<Sink>;
type ReadHandle = SharedHandle<Source>;
@@ -62,9 +62,7 @@ pub fn io_bindings<'a>(
]) + ConstTree::Tree(
std_streams
.into_iter()
.map(|(n, at)| {
(i.i(n), ConstTree::clause(ast::Clause::Atom(Atom(at))))
})
.map(|(n, at)| (i.i(n), ConstTree::clause(ast::Clause::Atom(Atom(at)))))
.collect(),
),
)

View File

@@ -5,12 +5,13 @@ use super::Canceller;
use crate::interpreted::ExprInst;
pub type SyncResult<T> = (T, Box<dyn Any + Send>);
/// Output from handlers contains the resource being processed and any Orchid
/// handlers executed as a result of the operation
pub type HandlerRes<T> = (T, Vec<ExprInst>);
pub type SyncOperation<T> =
Box<dyn FnOnce(T, Canceller) -> SyncResult<T> + Send>;
pub type SyncOpResultHandler<T> = Box<
dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>)
+ Send,
dyn FnOnce(T, Box<dyn Any + Send>, Canceller) -> (T, Vec<ExprInst>) + Send,
>;
struct SyncQueueItem<T> {
@@ -43,10 +44,7 @@ pub struct BusyState<T> {
}
impl<T> BusyState<T> {
pub fn new<U: 'static + Send>(
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>)
+ Send
+ 'static,
handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
) -> Self {
BusyState {
handler: Box::new(|t, payload, cancel| {
@@ -65,8 +63,8 @@ impl<T> BusyState<T> {
pub fn enqueue<U: 'static + Send>(
&mut self,
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + Send + 'static,
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + Send + 'static,
handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
early_cancel: impl FnOnce(T) -> HandlerRes<T> + Send + 'static,
) -> Option<Canceller> {
if self.seal.is_some() {
return None;
@@ -80,28 +78,31 @@ impl<T> BusyState<T> {
(t, Box::new(r))
}),
handler: Box::new(|t, u, c| {
let u = u.downcast().expect("mismatched handler and operation");
let u: Box<U> = u.downcast().expect("mismatched handler and operation");
handler(t, *u, c)
}),
});
Some(cancelled)
}
pub fn seal(&mut self, recipient: impl FnOnce(T) -> Vec<ExprInst> + Send + 'static) {
pub fn seal(
&mut self,
recipient: impl FnOnce(T) -> Vec<ExprInst> + Send + 'static,
) {
assert!(self.seal.is_none(), "Already sealed");
self.seal = Some(Box::new(recipient))
}
pub fn is_sealed(&self) -> bool { self.seal.is_some() }
pub fn rotate<U: Send + 'static>(
pub fn rotate(
mut self,
instance: T,
result: U,
result: Box<dyn Any + Send>,
cancelled: Canceller,
) -> NextItemReport<T> {
let (mut instance, mut events) =
(self.handler)(instance, Box::new(result), cancelled);
(self.handler)(instance, result, cancelled);
let next_item = loop {
if let Some(candidate) = self.queue.pop_front() {
if candidate.cancelled.is_cancelled() {

View File

@@ -5,5 +5,6 @@ mod busy;
mod canceller;
mod system;
pub use busy::HandlerRes;
pub use canceller::Canceller;
pub use system::{SealedOrTaken, SeqScheduler, SharedHandle, SharedState};

View File

@@ -8,8 +8,8 @@ use hashbrown::HashMap;
use itertools::Itertools;
use trait_set::trait_set;
use super::busy::{BusyState, NextItemReportKind};
use super::Canceller;
use super::busy::{BusyState, NextItemReportKind, SyncOperation};
use super::{Canceller, HandlerRes};
use crate::error::AssertionError;
use crate::facade::{IntoSystem, System};
use crate::foreign::cps_box::{init_cps, CPSBox};
@@ -80,13 +80,10 @@ impl<T> SharedHandle<T> {
/// is to return values synchronously after they have been removed with
/// [SyncHandle::untake].
pub fn untake(&self, value: T) -> Result<(), T> {
take_with_output(
&mut *self.0.lock().unwrap(),
|state| match state {
take_with_output(&mut *self.0.lock().unwrap(), |state| match state {
SharedResource::Taken => (SharedResource::Free(value), Ok(())),
_ => (state, Err(value)),
},
)
})
}
}
impl<T> Clone for SharedHandle<T> {
@@ -144,7 +141,7 @@ pub fn is_taken_error(x: ExprInst) -> XfnResult<bool> {
trait_set! {
/// The part of processing a blocking I/O task that cannot be done on a remote
/// thread, eg. because it accesses other systems or Orchid code.
trait NonSendFn = FnOnce(Box<dyn Any>, SeqScheduler) -> Vec<ExprInst>;
trait NonSendFn = FnOnce(Box<dyn Any + Send>, SeqScheduler) -> Vec<ExprInst>;
}
struct SyncReply {
@@ -198,9 +195,9 @@ impl SeqScheduler {
pub fn schedule<T: Send + 'static, U: Send + 'static>(
&self,
handle: SharedHandle<T>,
operation: impl FnOnce(T, Canceller) -> (T, U) + Sync + Send + 'static,
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + Sync + Send + 'static,
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + Sync + Send + 'static,
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
early_cancel: impl FnOnce(T) -> HandlerRes<T> + Send + 'static,
) -> Result<Canceller, SealedOrTaken> {
take_with_output(&mut *handle.0.lock().unwrap(), {
let handle = handle.clone();
@@ -216,7 +213,11 @@ impl SeqScheduler {
SharedResource::Free(t) => {
let cancelled = Canceller::new();
drop(early_cancel); // cannot possibly be useful
self.submit(t, handle, cancelled.clone(), operation);
let op_erased: SyncOperation<T> = Box::new(|t, c| {
let (t, u) = operation(t, c);
(t, Box::new(u))
});
self.submit(t, handle, cancelled.clone(), op_erased);
(SharedResource::Busy(BusyState::new(handler)), Ok(cancelled))
},
}
@@ -233,9 +234,11 @@ impl SeqScheduler {
) -> Canceller {
let cancelled = Canceller::new();
let canc1 = cancelled.clone();
let opid = self.0.pending.borrow_mut().insert(Box::new(|data, _| {
let opid = self.0.pending.borrow_mut().insert(Box::new(
|data: Box<dyn Any + Send>, _| {
handler(*data.downcast().expect("This is associated by ID"), canc1)
}));
},
));
let canc1 = cancelled.clone();
let mut port = self.0.port.clone();
self.0.pool.submit(Box::new(move || {
@@ -251,9 +254,7 @@ impl SeqScheduler {
handle: SharedHandle<T>,
seal: impl FnOnce(T) -> Vec<ExprInst> + Sync + Send + 'static,
) -> Result<Vec<ExprInst>, SealedOrTaken> {
take_with_output(
&mut *handle.0.lock().unwrap(),
|state| match state {
take_with_output(&mut *handle.0.lock().unwrap(), |state| match state {
SharedResource::Busy(mut b) if !b.is_sealed() => {
b.seal(seal);
(SharedResource::Busy(b), Ok(Vec::new()))
@@ -261,8 +262,7 @@ impl SeqScheduler {
SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
},
)
})
}
/// Asynchronously recursive function to schedule a new task for execution and
@@ -270,18 +270,18 @@ impl SeqScheduler {
/// from the callback passed to the [AsynchSystem] so that if the task is
/// never resolved but the [AsynchSystem] through which the resolving event
/// would arrive is dropped this [SeqScheduler] is also dropped.
fn submit<T: Send + 'static, U: Send + 'static>(
fn submit<T: Send + 'static>(
&self,
t: T,
handle: SharedHandle<T>,
cancelled: Canceller,
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
operation: SyncOperation<T>,
) {
// referenced by self until run, references handle
let opid = self.0.pending.borrow_mut().insert(Box::new({
let cancelled = cancelled.clone();
move |data, this| {
let (t, u): (T, U) =
move |data: Box<dyn Any + Send>, this: SeqScheduler| {
let (t, u): (T, Box<dyn Any + Send>) =
*data.downcast().expect("This is associated by ID");
let handle2 = handle.clone();
take_with_output(&mut *handle.0.lock().unwrap(), |state| {

View File

@@ -1,11 +1,10 @@
use crate::foreign::{xfn_1ary, xfn_2ary, XfnResult, Atom};
use super::Numeric;
use crate::error::AssertionError;
use crate::foreign::{xfn_1ary, xfn_2ary, Atom, XfnResult};
use crate::interner::Interner;
use crate::representations::interpreted::Clause;
use crate::error::AssertionError;
use crate::{ConstTree, Location, OrcString};
use super::Numeric;
/// Takes a boolean and two branches, runs the first if the bool is true, the
/// second if it's false.
// Even though it's a ternary function, IfThenElse is implemented as an unary
@@ -23,7 +22,8 @@ pub fn if_then_else(b: bool) -> XfnResult<Clause> {
/// - both are bool,
/// - both are either uint or num
pub fn equals(a: Atom, b: Atom) -> XfnResult<bool> {
let (a, b) = match (a.try_downcast::<OrcString>(), b.try_downcast::<OrcString>()) {
let (a, b) =
match (a.try_downcast::<OrcString>(), b.try_downcast::<OrcString>()) {
(Ok(a), Ok(b)) => return Ok(a == b),
(Err(a), Err(b)) => (a, b),
_ => return Ok(false),

View File

@@ -3,12 +3,12 @@ import std::panic
-- utilities for using lists as pairs
export const fst := \l. (
const fst := \l. (
list::get l 0
(panic "nonempty expected")
\x.x
)
export const snd := \l. (
const snd := \l. (
list::get l 1
(panic "2 elements expected")
\x.x

View File

@@ -4,15 +4,15 @@ mod arithmetic_error;
mod binary;
mod bool;
mod conv;
mod exit_status;
mod inspect;
mod number;
mod panic;
mod state;
mod stl_system;
mod string;
mod exit_status;
pub use arithmetic_error::ArithmeticError;
pub use binary::Binary;
pub use exit_status::ExitStatus;
pub use number::Numeric;
pub use stl_system::StlConfig;
pub use exit_status::ExitStatus;

View File

@@ -4,7 +4,7 @@ use ordered_float::NotNan;
use super::ArithmeticError;
use crate::error::AssertionError;
use crate::foreign::{xfn_2ary, ExternError, ToClause, XfnResult, Atomic};
use crate::foreign::{xfn_2ary, Atomic, ExternError, ToClause, XfnResult};
use crate::interpreted::TryFromExprInst;
use crate::representations::interpreted::{Clause, ExprInst};
use crate::{ConstTree, Interner, Location};

View File

@@ -1,4 +1,5 @@
use std::{rc::Rc, sync::Arc};
use std::rc::Rc;
use std::sync::Arc;
pub fn rc_to_owned<T: Clone>(rc: Rc<T>) -> T {
Rc::try_unwrap(rc).unwrap_or_else(|rc| rc.as_ref().clone())