Skip to content

Commit

Permalink
fix(repl): Evaluate IO expressions automatically in the repl
Browse files Browse the repository at this point in the history
Broken accidentally when let bindings without a body expression (`let x = 3`) were accepted in the repl

Fixes #334
  • Loading branch information
Marwes committed Sep 11, 2017
1 parent 6b6a2f6 commit d9e6e95
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 34 deletions.
13 changes: 5 additions & 8 deletions repl/src/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use vm::internal::ValuePrinter;
use vm::thread::{RootStr, RootedValue, Thread, ThreadInternal};

use gluon::{new_vm, Compiler, Result as GluonResult, RootedThread};
use gluon::compiler_pipeline::Executable;
use gluon::compiler_pipeline::{run_io, Executable};

fn type_of_expr(args: WithVM<RootStr>) -> IO<Result<String, String>> {
let WithVM { vm, value: args } = args;
Expand Down Expand Up @@ -191,11 +191,12 @@ fn eval_line_(vm: &Thread, line: &str) -> GluonResult<String> {
}
};
let mut eval_expr;
let value = match let_or_expr {
let (value, typ) = match let_or_expr {
Ok(expr) => {
eval_expr = expr;
eval_expr
.run_expr(&mut compiler, vm, "<line>", line, None)
.and_then(|v| run_io(vm, v))
.wait()?
}
Err(let_binding) => {
Expand All @@ -214,16 +215,12 @@ fn eval_line_(vm: &Thread, line: &str) -> GluonResult<String> {
.run_expr(&mut compiler, vm, "<line>", line, None)
.wait()?;
set_globals(vm, &unpack_pattern, &value.typ, &value.value)?;
value
(value.value, value.typ)
}
};

let env = vm.global_env().get_env();
Ok(
ValuePrinter::new(&*env, &value.typ, *value.value)
.width(80)
.to_string(),
)
Ok(ValuePrinter::new(&*env, &typ, *value).width(80).to_string())
}

fn set_globals(
Expand Down
21 changes: 21 additions & 0 deletions src/compiler_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,3 +507,24 @@ where
.serialize_state(serializer, &SeSeed::new(thread))
.map_err(Either::Right)
}

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

let ExecuteValue {
typ: actual, value, ..
} = v;
if check_signature(&*vm.get_env(), &actual, &IO::<A>::make_type(vm)) {
vm.execute_io(*value)
.map(move |(_, value)| (vm.root_value(value), actual))
.map_err(Error::from)
.boxed()
} else {
FutureValue::sync(Ok((value, actual))).boxed()
}
}
37 changes: 11 additions & 26 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,8 @@ impl Compiler {
expr_str: &str,
expected_type: Option<&ArcType>,
) -> Result<(SpannedExpr<Symbol>, ArcType)> {
let TypecheckValue { expr, typ } = expr_str.typecheck_expected(
self,
vm,
file,
expr_str,
expected_type,
)?;
let TypecheckValue { expr, typ } =
expr_str.typecheck_expected(self, vm, file, expr_str, expected_type)?;
Ok((expr, typ))
}

Expand Down Expand Up @@ -339,9 +334,10 @@ impl Compiler {
// Use the import macro's path resolution if it exists so that we mimick the import
// macro as close as possible
let opt_macro = vm.get_macros().get("import");
match opt_macro.as_ref().and_then(
|mac| mac.downcast_ref::<Import>(),
) {
match opt_macro
.as_ref()
.and_then(|mac| mac.downcast_ref::<Import>())
{
Some(import) => Ok(import.read_file(filename)?),
None => {
let mut buffer = StdString::new();
Expand Down Expand Up @@ -432,7 +428,9 @@ impl Compiler {
expr_str
.run_expr(self, vm, name, expr_str, Some(&expected))
.and_then(move |v| {
let ExecuteValue { typ: actual, value, .. } = v;
let ExecuteValue {
typ: actual, value, ..
} = v;
unsafe {
FutureValue::sync(match T::from_value(vm, Variants::new(&value)) {
Some(value) => Ok((value, actual)),
Expand Down Expand Up @@ -468,24 +466,11 @@ impl Compiler {
T: Getable<'vm> + VmType + Send + 'vm,
T::Type: Sized,
{
use check::check_signature;
use vm::api::IO;
use vm::api::generic::A;

let expected = T::make_type(vm);
expr_str
.run_expr(self, vm, name, expr_str, Some(&expected))
.and_then(move |v| {
let ExecuteValue { typ: actual, value, .. } = v;
if check_signature(&*vm.get_env(), &actual, &IO::<A>::make_type(vm)) {
vm.execute_io(*value)
.map(move |(_, value)| (value, expected, actual))
.map_err(Error::from)
} else {
FutureValue::Value(Ok((*value, expected, actual)))
}
})
.and_then(move |(value, expected, actual)| unsafe {
.and_then(move |v| run_io(vm, v))
.and_then(move |(value, actual)| unsafe {
FutureValue::sync(match T::from_value(vm, Variants::new(&value)) {
Some(value) => Ok((value, actual)),
None => Err(Error::from(VmError::WrongType(expected, actual))),
Expand Down

0 comments on commit d9e6e95

Please sign in to comment.