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 //! Various errors the pipeline can produce
mod assertion_error;
mod conflicting_roles; mod conflicting_roles;
mod import_all; mod import_all;
mod no_targets; mod no_targets;
mod not_exported; mod not_exported;
mod parse_error_with_tokens; mod parse_error_with_tokens;
mod project_error; mod project_error;
mod runtime_error;
mod too_many_supers; mod too_many_supers;
mod unexpected_directory; mod unexpected_directory;
mod visibility_mismatch; mod visibility_mismatch;
mod assertion_error;
mod runtime_error;
pub use assertion_error::AssertionError;
pub use conflicting_roles::ConflictingRoles; pub use conflicting_roles::ConflictingRoles;
pub use import_all::ImportAll; pub use import_all::ImportAll;
pub use no_targets::NoTargets; pub use no_targets::NoTargets;
pub use not_exported::NotExported; pub use not_exported::NotExported;
pub use parse_error_with_tokens::ParseErrorWithTokens; pub use parse_error_with_tokens::ParseErrorWithTokens;
pub use project_error::{ErrorPosition, ProjectError, ProjectResult}; pub use project_error::{ErrorPosition, ProjectError, ProjectResult};
pub use runtime_error::RuntimeError;
pub use too_many_supers::TooManySupers; pub use too_many_supers::TooManySupers;
pub use unexpected_directory::UnexpectedDirectory; pub use unexpected_directory::UnexpectedDirectory;
pub use visibility_mismatch::VisibilityMismatch; 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 /// Functionality the interpreter needs to handle a value
pub trait Atomic: pub trait Atomic: Any + Debug + DynClone + StrictEq + Responder + Send
Any + Debug + DynClone + StrictEq + Responder + Send
where where
Self: 'static, Self: 'static,
{ {

View File

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

View File

@@ -11,7 +11,7 @@ mod inert;
use std::rc::Rc; use std::rc::Rc;
pub use atom::{Atom, Atomic, AtomicResult, AtomicReturn, StrictEq}; 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::{ pub use fn_bridge::constructors::{
xfn_1ary, xfn_2ary, xfn_3ary, xfn_4ary, xfn_5ary, xfn_6ary, xfn_7ary, xfn_1ary, xfn_2ary, xfn_3ary, xfn_4ary, xfn_5ary, xfn_6ary, xfn_7ary,
xfn_8ary, xfn_9ary, xfn_8ary, xfn_9ary,

View File

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

View File

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

View File

@@ -183,7 +183,9 @@ impl ProjectError for NaNLiteral {
pub struct LiteralOverflow(pub Location); pub struct LiteralOverflow(pub Location);
impl ProjectError for LiteralOverflow { 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() } 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()) Ok(Vec::new())
} else { } else {
parse_module_body(Stream::from_slice(&tokens), &ctx).map_err(|error| { 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 itertools::Itertools;
use ordered_float::NotNan; use ordered_float::NotNan;
use super::LexerPlugin;
use super::context::Context; use super::context::Context;
use super::errors::{FloatPlacehPrio, NoCommentEnd}; 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::ast::{PHClass, Placeholder};
use crate::error::{ProjectResult, ProjectError}; use crate::error::{ProjectError, ProjectResult};
use crate::foreign::Atom; use crate::foreign::Atom;
use crate::interner::Tok; 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::parse::string::lex_string;
use crate::systems::stl::Numeric; use crate::systems::stl::Numeric;
use crate::utils::pure_seq::next; use crate::utils::pure_seq::next;
@@ -210,7 +210,7 @@ pub fn lex(
ctx: &impl Context, ctx: &impl Context,
) -> ProjectResult<Vec<Entry>> { ) -> ProjectResult<Vec<Entry>> {
let mut prev_len = data.len() + 1; let mut prev_len = data.len() + 1;
'tail:loop { 'tail: loop {
if prev_len == data.len() { if prev_len == data.len() {
panic!("got stuck at {data:?}, parsed {:?}", tokens.last().unwrap()); panic!("got stuck at {data:?}, parsed {:?}", tokens.last().unwrap());
} }
@@ -234,7 +234,8 @@ pub fn lex(
} }
for (prefix, lexeme) in lit_table() { for (prefix, lexeme) in lit_table() {
if let Some(tail) = data.strip_prefix(prefix) { 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; data = tail;
continue 'tail; continue 'tail;
} }
@@ -267,7 +268,11 @@ pub fn lex(
if tail.chars().next().map_or(false, numstart) { if tail.chars().next().map_or(false, numstart) {
let (num, post_num) = split_filter(tail, numchar); let (num, post_num) = split_filter(tail, numchar);
if let Some(tail) = post_num.strip_prefix("=>") { 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); let location = ctx.location(num.len() + 3, tail);
tokens.push(Entry::new(location, lexeme)); tokens.push(Entry::new(location, lexeme));
data = tail; data = tail;
@@ -281,7 +286,8 @@ pub fn lex(
if !name.is_empty() { if !name.is_empty() {
let name = ctx.interner().i(name); let name = ctx.interner().i(name);
let location = ctx.location(name.len() + 1, tail); 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)); tokens.push(Entry::new(location, lexeme));
data = tail; data = tail;
continue 'tail; continue 'tail;
@@ -302,7 +308,8 @@ pub fn lex(
.map_err(|e| e.into_proj(num_str.len(), tail, ctx)) .map_err(|e| e.into_proj(num_str.len(), tail, ctx))
.and_then(|num| { .and_then(|num| {
Ok(unwrap_or!(num => Numeric::Uint; { 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)) .map(|p| (p, num_str.len() + 1, tail))

View File

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

View File

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

View File

@@ -111,7 +111,10 @@ mod test {
let (data, tail) = lex_string(source, &MockContext(&i)) let (data, tail) = lex_string(source, &MockContext(&i))
.expect("the snippet starts with a quote") .expect("the snippet starts with a quote")
.expect("it contains a valid string"); .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"); assert_eq!(tail, " - says the programmer");
} }
} }

View File

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

View File

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

View File

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

View File

@@ -19,10 +19,9 @@ fn collect_paths_cls_rec(
match cls { match cls {
postmacro::Clause::Atom(_) | postmacro::Clause::ExternFn(_) => None, postmacro::Clause::Atom(_) | postmacro::Clause::ExternFn(_) => None,
postmacro::Clause::Constant(_) => None, postmacro::Clause::Constant(_) => None,
postmacro::Clause::LambdaArg(h) => postmacro::Clause::LambdaArg(h) => match *h != depth {
match *h != depth {
true => None, true => None,
false => Some(PathSet::pick()) false => Some(PathSet::pick()),
}, },
postmacro::Clause::Lambda(b) => collect_paths_expr_rec(b, depth + 1), postmacro::Clause::Lambda(b) => collect_paths_expr_rec(b, depth + 1),
postmacro::Clause::Apply(f, x) => { postmacro::Clause::Apply(f, x) => {
@@ -43,7 +42,8 @@ pub fn clause(cls: &postmacro::Clause) -> interpreted::Clause {
postmacro::Clause::Constant(name) => postmacro::Clause::Constant(name) =>
interpreted::Clause::Constant(name.clone()), interpreted::Clause::Constant(name.clone()),
postmacro::Clause::Atom(a) => interpreted::Clause::Atom(a.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) => 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()) },
postmacro::Clause::Lambda(body) => interpreted::Clause::Lambda { 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 super::{update_first_seq, RuleError, VectreeMatcher};
use crate::ast::Rule; use crate::ast::Rule;
use crate::interner::Interner; use crate::interner::Interner;
use crate::Sym;
use crate::parse::print_nat16; use crate::parse::print_nat16;
use crate::Sym;
#[derive(Debug)] #[derive(Debug)]
pub struct CachedRule<M: Matcher> { pub struct CachedRule<M: Matcher> {

View File

@@ -51,8 +51,9 @@ impl Display for RuleError {
Self::Multiple(key) => { Self::Multiple(key) => {
write!(f, "Key {key} appears multiple times in match pattern") write!(f, "Key {key} appears multiple times in match pattern")
}, },
Self::VecNeighbors(left, right) => Self::VecNeighbors(left, right) => {
write!(f, "vectorials {left} and {right} are next to each other"), 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> { pub fn apply_expr(template: &RuleExpr, state: &State) -> Vec<RuleExpr> {
let Expr { location, value } = template; let Expr { location, value } = template;
match value { match value {
Clause::Atom(_) | Clause::Name(_) | Clause::ExternFn(_) => Clause::Atom(_) | Clause::Name(_) | Clause::ExternFn(_) => {
vec![template.clone()], vec![template.clone()]
},
Clause::S(c, body) => vec![Expr { Clause::S(c, body) => vec![Expr {
location: location.clone(), location: location.clone(),
value: Clause::S(*c, Rc::new(apply_exprv(body.as_slice(), state))), 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::interpreter::HandlerTable;
use crate::pipeline::file_loader::embed_to_map; use crate::pipeline::file_loader::embed_to_map;
use crate::systems::codegen::call; use crate::systems::codegen::call;
use crate::systems::stl::Numeric;
use crate::utils::poller::{PollEvent, Poller}; use crate::utils::poller::{PollEvent, Poller};
use crate::utils::unwrap_or; use crate::utils::unwrap_or;
use crate::{ConstTree, Interner}; use crate::{ConstTree, Interner};
@@ -28,8 +29,8 @@ struct Timer {
delay: NotNan<f64>, delay: NotNan<f64>,
} }
pub fn set_timer(recurring: bool, delay: NotNan<f64>) -> XfnResult<Clause> { pub fn set_timer(recurring: bool, delay: Numeric) -> XfnResult<Clause> {
Ok(init_cps(2, Timer { recurring, delay })) Ok(init_cps(2, Timer { recurring, delay: delay.as_float() }))
} }
#[derive(Clone)] #[derive(Clone)]
@@ -38,9 +39,7 @@ impl CancelTimer {
pub fn new(f: impl Fn() + Send + 'static) -> Self { pub fn new(f: impl Fn() + Send + 'static) -> Self {
Self(Arc::new(Mutex::new(f))) Self(Arc::new(Mutex::new(f)))
} }
pub fn cancel(&self) { pub fn cancel(&self) { self.0.lock().unwrap()() }
self.0.lock().unwrap()()
}
} }
impl Debug for CancelTimer { impl Debug for CancelTimer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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)] #[cfg(test)]
mod test { mod test {
use crate::{systems::codegen::tuple, foreign::Atomic}; use crate::foreign::Atomic;
use crate::systems::codegen::tuple;
#[test] #[test]
fn tuple_printer() { fn tuple_printer() {

View File

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

View File

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

View File

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

View File

@@ -8,8 +8,8 @@ use hashbrown::HashMap;
use itertools::Itertools; use itertools::Itertools;
use trait_set::trait_set; use trait_set::trait_set;
use super::busy::{BusyState, NextItemReportKind}; use super::busy::{BusyState, NextItemReportKind, SyncOperation};
use super::Canceller; use super::{Canceller, HandlerRes};
use crate::error::AssertionError; use crate::error::AssertionError;
use crate::facade::{IntoSystem, System}; use crate::facade::{IntoSystem, System};
use crate::foreign::cps_box::{init_cps, CPSBox}; 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 /// is to return values synchronously after they have been removed with
/// [SyncHandle::untake]. /// [SyncHandle::untake].
pub fn untake(&self, value: T) -> Result<(), T> { pub fn untake(&self, value: T) -> Result<(), T> {
take_with_output( take_with_output(&mut *self.0.lock().unwrap(), |state| match state {
&mut *self.0.lock().unwrap(),
|state| match state {
SharedResource::Taken => (SharedResource::Free(value), Ok(())), SharedResource::Taken => (SharedResource::Free(value), Ok(())),
_ => (state, Err(value)), _ => (state, Err(value)),
}, })
)
} }
} }
impl<T> Clone for SharedHandle<T> { impl<T> Clone for SharedHandle<T> {
@@ -144,7 +141,7 @@ pub fn is_taken_error(x: ExprInst) -> XfnResult<bool> {
trait_set! { trait_set! {
/// The part of processing a blocking I/O task that cannot be done on a remote /// 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. /// 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 { struct SyncReply {
@@ -198,9 +195,9 @@ impl SeqScheduler {
pub fn schedule<T: Send + 'static, U: Send + 'static>( pub fn schedule<T: Send + 'static, U: Send + 'static>(
&self, &self,
handle: SharedHandle<T>, handle: SharedHandle<T>,
operation: impl FnOnce(T, Canceller) -> (T, U) + Sync + Send + 'static, operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static,
handler: impl FnOnce(T, U, Canceller) -> (T, Vec<ExprInst>) + Sync + Send + 'static, handler: impl FnOnce(T, U, Canceller) -> HandlerRes<T> + Send + 'static,
early_cancel: impl FnOnce(T) -> (T, Vec<ExprInst>) + Sync + Send + 'static, early_cancel: impl FnOnce(T) -> HandlerRes<T> + Send + 'static,
) -> Result<Canceller, SealedOrTaken> { ) -> Result<Canceller, SealedOrTaken> {
take_with_output(&mut *handle.0.lock().unwrap(), { take_with_output(&mut *handle.0.lock().unwrap(), {
let handle = handle.clone(); let handle = handle.clone();
@@ -216,7 +213,11 @@ impl SeqScheduler {
SharedResource::Free(t) => { SharedResource::Free(t) => {
let cancelled = Canceller::new(); let cancelled = Canceller::new();
drop(early_cancel); // cannot possibly be useful 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)) (SharedResource::Busy(BusyState::new(handler)), Ok(cancelled))
}, },
} }
@@ -233,9 +234,11 @@ impl SeqScheduler {
) -> Canceller { ) -> Canceller {
let cancelled = Canceller::new(); let cancelled = Canceller::new();
let canc1 = cancelled.clone(); 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) handler(*data.downcast().expect("This is associated by ID"), canc1)
})); },
));
let canc1 = cancelled.clone(); let canc1 = cancelled.clone();
let mut port = self.0.port.clone(); let mut port = self.0.port.clone();
self.0.pool.submit(Box::new(move || { self.0.pool.submit(Box::new(move || {
@@ -251,9 +254,7 @@ impl SeqScheduler {
handle: SharedHandle<T>, handle: SharedHandle<T>,
seal: impl FnOnce(T) -> Vec<ExprInst> + Sync + Send + 'static, seal: impl FnOnce(T) -> Vec<ExprInst> + Sync + Send + 'static,
) -> Result<Vec<ExprInst>, SealedOrTaken> { ) -> Result<Vec<ExprInst>, SealedOrTaken> {
take_with_output( take_with_output(&mut *handle.0.lock().unwrap(), |state| match state {
&mut *handle.0.lock().unwrap(),
|state| match state {
SharedResource::Busy(mut b) if !b.is_sealed() => { SharedResource::Busy(mut b) if !b.is_sealed() => {
b.seal(seal); b.seal(seal);
(SharedResource::Busy(b), Ok(Vec::new())) (SharedResource::Busy(b), Ok(Vec::new()))
@@ -261,8 +262,7 @@ impl SeqScheduler {
SharedResource::Busy(_) => (state, Err(SealedOrTaken)), SharedResource::Busy(_) => (state, Err(SealedOrTaken)),
SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)), SharedResource::Taken => (SharedResource::Taken, Err(SealedOrTaken)),
SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))), SharedResource::Free(t) => (SharedResource::Taken, Ok(seal(t))),
}, })
)
} }
/// Asynchronously recursive function to schedule a new task for execution and /// 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 /// from the callback passed to the [AsynchSystem] so that if the task is
/// never resolved but the [AsynchSystem] through which the resolving event /// never resolved but the [AsynchSystem] through which the resolving event
/// would arrive is dropped this [SeqScheduler] is also dropped. /// would arrive is dropped this [SeqScheduler] is also dropped.
fn submit<T: Send + 'static, U: Send + 'static>( fn submit<T: Send + 'static>(
&self, &self,
t: T, t: T,
handle: SharedHandle<T>, handle: SharedHandle<T>,
cancelled: Canceller, cancelled: Canceller,
operation: impl FnOnce(T, Canceller) -> (T, U) + Send + 'static, operation: SyncOperation<T>,
) { ) {
// referenced by self until run, references handle // referenced by self until run, references handle
let opid = self.0.pending.borrow_mut().insert(Box::new({ let opid = self.0.pending.borrow_mut().insert(Box::new({
let cancelled = cancelled.clone(); let cancelled = cancelled.clone();
move |data, this| { move |data: Box<dyn Any + Send>, this: SeqScheduler| {
let (t, u): (T, U) = let (t, u): (T, Box<dyn Any + Send>) =
*data.downcast().expect("This is associated by ID"); *data.downcast().expect("This is associated by ID");
let handle2 = handle.clone(); let handle2 = handle.clone();
take_with_output(&mut *handle.0.lock().unwrap(), |state| { 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::interner::Interner;
use crate::representations::interpreted::Clause; use crate::representations::interpreted::Clause;
use crate::error::AssertionError;
use crate::{ConstTree, Location, OrcString}; use crate::{ConstTree, Location, OrcString};
use super::Numeric;
/// Takes a boolean and two branches, runs the first if the bool is true, the /// Takes a boolean and two branches, runs the first if the bool is true, the
/// second if it's false. /// second if it's false.
// Even though it's a ternary function, IfThenElse is implemented as an unary // 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 bool,
/// - both are either uint or num /// - both are either uint or num
pub fn equals(a: Atom, b: Atom) -> XfnResult<bool> { 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), (Ok(a), Ok(b)) => return Ok(a == b),
(Err(a), Err(b)) => (a, b), (Err(a), Err(b)) => (a, b),
_ => return Ok(false), _ => return Ok(false),

View File

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

View File

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

View File

@@ -4,7 +4,7 @@ use ordered_float::NotNan;
use super::ArithmeticError; use super::ArithmeticError;
use crate::error::AssertionError; 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::interpreted::TryFromExprInst;
use crate::representations::interpreted::{Clause, ExprInst}; use crate::representations::interpreted::{Clause, ExprInst};
use crate::{ConstTree, Interner, Location}; 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 { pub fn rc_to_owned<T: Clone>(rc: Rc<T>) -> T {
Rc::try_unwrap(rc).unwrap_or_else(|rc| rc.as_ref().clone()) Rc::try_unwrap(rc).unwrap_or_else(|rc| rc.as_ref().clone())