Skip to content

Commit

Permalink
fix(vm): Allow async functions to run within the io primitives
Browse files Browse the repository at this point in the history
  • Loading branch information
Marwes committed Dec 11, 2017
1 parent 6d78862 commit e6f611a
Show file tree
Hide file tree
Showing 19 changed files with 419 additions and 176 deletions.
1 change: 1 addition & 0 deletions repl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ gluon_completion = { path = "../completion", version = "0.6.2" } # GLUON
gluon_format = { version = "0.6.2", path = "../format" } # GLUON

futures = "0.1.11"
tokio-core = "0.1"
clap = "2.22.0"
log = "0.3.6"
env_logger = { version = "0.3.4", optional = true }
Expand Down
13 changes: 8 additions & 5 deletions repl/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate env_logger;
extern crate futures;
#[macro_use]
extern crate log;
extern crate tokio_core;
extern crate walkdir;

extern crate gluon;
Expand Down Expand Up @@ -157,13 +158,15 @@ fn main() {
// Need the extra stack size when compiling the program using the msvc compiler
::std::thread::Builder::new()
.stack_size(2 * 1024 * 1024)
.spawn(|| if let Err(err) = run() {
let stderr = &mut io::stderr();
let errmsg = "Error writing to stderr";
.spawn(|| {
if let Err(err) = run() {
let stderr = &mut io::stderr();
let errmsg = "Error writing to stderr";

write!(stderr, "error: {}", err).expect(errmsg);
write!(stderr, "error: {}", err).expect(errmsg);

::std::process::exit(1);
::std::process::exit(1);
}
})
.unwrap()
.join()
Expand Down
2 changes: 1 addition & 1 deletion repl/src/repl.glu
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let load_file filename : String -> IO String =
let modulename = string.slice filename last_slash (string.len filename - 3)
let action =
do expr = io.read_file_to_string filename
do result = io.load_script modulename expr
do result = io.load_script modulename expr
wrap result
io.catch action (\err -> wrap err)

Expand Down
8 changes: 5 additions & 3 deletions repl/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use base::symbol::{Symbol, SymbolModule};
use base::types::ArcType;
use parser::parse_partial_let_or_expr;
use vm::{self, Error as VMError};
use vm::api::{Function, Userdata, VmType, WithVM, IO};
use vm::api::{OwnedFunction, Userdata, VmType, WithVM, IO};
use vm::gc::{Gc, Traverseable};
use vm::internal::ValuePrinter;
use vm::thread::{RootStr, RootedValue, Thread, ThreadInternal};
Expand Down Expand Up @@ -311,9 +311,11 @@ fn compile_repl(vm: &Thread) -> Result<(), Box<StdError + Send + Sync>> {
pub fn run() -> Result<(), Box<StdError + Send + Sync>> {
let vm = new_vm();
compile_repl(&vm)?;
let mut repl: Function<&Thread, fn(()) -> IO<()>> = vm.get_global("repl")?;
let mut repl: OwnedFunction<fn(()) -> IO<()>> = vm.get_global("repl")?;
debug!("Starting repl");
repl.call(())?;

let mut core = ::tokio_core::reactor::Core::new()?;
core.run(repl.call_async(()))?;
Ok(())
}

Expand Down
140 changes: 96 additions & 44 deletions src/compiler_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! difficult to forget a stage.

use std::borrow::{Borrow, BorrowMut};
use std::ops::Deref;
use std::result::Result as StdResult;

#[cfg(feature = "serde")]
Expand All @@ -25,10 +26,27 @@ use vm::core;
use vm::compiler::CompiledModule;
use vm::future::{BoxFutureValue, FutureValue};
use vm::macros::MacroExpander;
use vm::thread::{RootedValue, Thread, ThreadInternal};
use vm::thread::{Execute, RootedValue, Thread, ThreadInternal, VmRoot};

use {Compiler, Error, Result};


fn execute<T, F>(vm: T, f: F) -> FutureValue<Execute<T>>
where
T: Deref<Target = Thread>,
F: for<'vm> FnOnce(&'vm Thread) -> FutureValue<Execute<&'vm Thread>>,
{
let opt = match f(&vm) {
FutureValue::Value(result) => Some(result.map(|v| v.1)),
FutureValue::Future(_) => None,
FutureValue::Polled => return FutureValue::Polled,
};
match opt {
Some(result) => FutureValue::Value(result.map(|v| (vm, v))),
None => FutureValue::Future(Execute::new(vm)),
}
}

pub type SalvageResult<T> = StdResult<T, (Option<T>, Error)>;

/// Result type of successful macro expansion
Expand Down Expand Up @@ -298,33 +316,40 @@ where
}

/// Result of successful execution
pub struct ExecuteValue<'vm, E> {
pub struct ExecuteValue<T, E>
where
T: Deref<Target = Thread>,
{
pub id: Symbol,
pub expr: E,
pub typ: ArcType,
pub value: RootedValue<&'vm Thread>,
pub value: RootedValue<T>,
}

pub trait Executable<'vm, Extra> {
type Expr;

fn run_expr(
fn run_expr<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
name: &str,
expr_str: &str,
arg: Extra,
) -> BoxFutureValue<'vm, ExecuteValue<'vm, Self::Expr>, Error>;
) -> BoxFutureValue<'vm, ExecuteValue<T, Self::Expr>, Error>
where
T: Send + VmRoot<'vm>;

fn load_script(
fn load_script<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
filename: &str,
expr_str: &str,
arg: Extra,
) -> BoxFutureValue<'vm, (), Error>;
) -> BoxFutureValue<'vm, (), Error>
where
T: Send + VmRoot<'vm>;
}
impl<'vm, C, Extra> Executable<'vm, Extra> for C
where
Expand All @@ -333,28 +358,34 @@ where
{
type Expr = C::Expr;

fn run_expr(
fn run_expr<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
name: &str,
expr_str: &str,
arg: Extra,
) -> BoxFutureValue<'vm, ExecuteValue<'vm, Self::Expr>, Error> {
match self.compile(compiler, vm, name, expr_str, arg) {
) -> BoxFutureValue<'vm, ExecuteValue<T, Self::Expr>, Error>
where
T: Send + VmRoot<'vm>,
{
match self.compile(compiler, &vm, name, expr_str, arg) {
Ok(v) => v.run_expr(compiler, vm, name, expr_str, ()),
Err(err) => FutureValue::Value(Err(err)),
}
}
fn load_script(
fn load_script<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
filename: &str,
expr_str: &str,
arg: Extra,
) -> BoxFutureValue<'vm, (), Error> {
match self.compile(compiler, vm, filename, expr_str, arg) {
) -> BoxFutureValue<'vm, (), Error>
where
T: Send + VmRoot<'vm>,
{
match self.compile(compiler, &vm, filename, expr_str, arg) {
Ok(v) => v.load_script(compiler, vm, filename, expr_str, ()),
Err(err) => FutureValue::Value(Err(err)),
}
Expand All @@ -366,14 +397,17 @@ where
{
type Expr = E;

fn run_expr(
fn run_expr<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
name: &str,
_expr_str: &str,
_: (),
) -> BoxFutureValue<'vm, ExecuteValue<'vm, Self::Expr>, Error> {
) -> BoxFutureValue<'vm, ExecuteValue<T, Self::Expr>, Error>
where
T: Send + VmRoot<'vm>,
{
let CompileValue {
expr,
typ,
Expand All @@ -383,13 +417,15 @@ where
let module_id = Symbol::from(format!("@{}", name));
module.function.id = module_id.clone();
let closure = try_future!(vm.global_env().new_global_thunk(module));
vm.call_thunk(closure)

let vm1 = vm.clone();
execute(vm1, |vm| vm.call_thunk(closure))
.map(|(vm, value)| {
ExecuteValue {
id: module_id,
expr: expr,
typ: typ,
value: vm.root_value(value),
value: vm.root_value_with_self(value),
}
})
.map_err(Error::from)
Expand All @@ -402,23 +438,28 @@ where
})
.boxed()
}
fn load_script(
fn load_script<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
filename: &str,
expr_str: &str,
_: (),
) -> BoxFutureValue<'vm, (), Error> {
) -> BoxFutureValue<'vm, (), Error>
where
T: Send + VmRoot<'vm>,
{
use check::metadata;

let run_io = compiler.run_io;
let filename = filename.to_string();

self.run_expr(compiler, vm, &filename, expr_str, ())
let vm1 = vm.clone();
let vm2 = vm.clone();
self.run_expr(compiler, vm1, &filename, expr_str, ())
.and_then(move |v| {
if run_io {
::compiler_pipeline::run_io(vm, v)
::compiler_pipeline::run_io(vm2, v)
} else {
FutureValue::sync(Ok(v)).boxed()
}
Expand Down Expand Up @@ -456,18 +497,21 @@ where
{
type Expr = ();

fn run_expr(
fn run_expr<T>(
self,
_compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
filename: &str,
_expr_str: &str,
_: (),
) -> BoxFutureValue<'vm, ExecuteValue<'vm, Self::Expr>, Error> {
) -> BoxFutureValue<'vm, ExecuteValue<T, Self::Expr>, Error>
where
T: Send + VmRoot<'vm>,
{
use vm::serialization::DeSeed;

let module: Module = try_future!(
DeSeed::new(vm)
DeSeed::new(&vm)
.deserialize(self.0)
.map_err(|err| err.to_string())
);
Expand All @@ -481,27 +525,31 @@ where
.boxed();
}
let typ = module.typ;
let vm1 = vm.clone();
let closure = try_future!(vm.global_env().new_global_thunk(module.module));
vm.call_thunk(closure)
execute(vm1, |vm| vm.call_thunk(closure))
.map(|(vm, value)| {
ExecuteValue {
id: module_id,
expr: (),
typ: typ,
value: vm.root_value(value),
value: vm.root_value_with_self(value),
}
})
.map_err(Error::from)
.boxed()
}
fn load_script(
fn load_script<T>(
self,
compiler: &mut Compiler,
vm: &'vm Thread,
vm: T,
name: &str,
_expr_str: &str,
_: (),
) -> BoxFutureValue<'vm, (), Error> {
) -> BoxFutureValue<'vm, (), Error>
where
T: Send + VmRoot<'vm>,
{
use vm::serialization::DeSeed;
use vm::internal::Global;

Expand All @@ -511,7 +559,7 @@ where
value,
id: _,
} = try_future!(
DeSeed::new(vm)
DeSeed::new(&vm)
.deserialize(self.0)
.map_err(|err| err.to_string())
);
Expand Down Expand Up @@ -557,25 +605,29 @@ where
.map_err(Either::Right)
}

pub fn run_io<'vm, E>(
vm: &'vm Thread,
v: ExecuteValue<'vm, E>,
) -> BoxFutureValue<'vm, ExecuteValue<'vm, E>, Error>
pub fn run_io<'vm, T, E>(
vm: T,
v: ExecuteValue<T, E>,
) -> BoxFutureValue<'vm, ExecuteValue<T, E>, Error>
where
E: Send + 'vm,
T: Send + VmRoot<'vm>,
{
use check::check_signature;
use vm::api::{VmType, IO};
use vm::api::generic::A;

if check_signature(&*vm.get_env(), &v.typ, &IO::<A>::make_forall_type(vm)) {
if check_signature(&*vm.get_env(), &v.typ, &IO::<A>::make_forall_type(&vm)) {
let ExecuteValue {
id,
expr,
typ,
value,
} = v;
vm.execute_io(*value)


let vm1 = vm.clone();
execute(vm1, |vm| vm.execute_io(*value))
.map(move |(_, value)| {
// The type of the new value will be `a` instead of `IO a`
let actual = resolve::remove_aliases_cow(&*vm.get_env(), &typ);
Expand All @@ -586,7 +638,7 @@ where
ExecuteValue {
id,
expr,
value: vm.root_value(value),
value: vm.root_value_with_self(value),
typ: actual,
}
})
Expand Down
Loading

0 comments on commit e6f611a

Please sign in to comment.