Skip to content

Commit 19c1a85

Browse files
committed
Lazy evaluation
1 parent 3960a94 commit 19c1a85

File tree

8 files changed

+459
-232
lines changed

8 files changed

+459
-232
lines changed

fathom/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ lalrpop-util = "0.19.5"
2727
lasso = { version = "0.6.0", features = ["multi-threaded", "ahasher", "inline-more"] }
2828
levenshtein = "1.0.5"
2929
logos = "0.12"
30-
once_cell = { version = "1.17.0", features = ["parking_lot"] }
30+
once_cell = { version = "1.17.0", features = ["parking_lot"] } # TODO: remove once `std::cell::once_cell` is stabilized
3131
pretty = "0.11.2"
3232
rpds = "0.12.0"
3333
scoped-arena = "0.4.1"

fathom/src/core/binary.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use std::fmt::Debug;
77
use std::slice::SliceIndex;
88
use std::sync::Arc;
99

10-
use crate::core::semantics::{self, ArcValue, Elim, Head, Value};
10+
use super::semantics::{EvalMode, LocalExprs};
11+
use crate::core::semantics::{self, ArcValue, Elim, Head, LazyValue, Value};
1112
use crate::core::{Const, Item, Module, Prim, Term, UIntStyle};
1213
use crate::env::{EnvLen, SharedEnv, UniqueEnv};
1314
use crate::source::{Span, Spanned};
@@ -254,8 +255,8 @@ impl fmt::Display for BufferError {
254255
impl std::error::Error for BufferError {}
255256

256257
pub struct Context<'arena, 'data> {
257-
item_exprs: UniqueEnv<ArcValue<'arena>>,
258-
local_exprs: SharedEnv<ArcValue<'arena>>,
258+
item_exprs: UniqueEnv<LazyValue<'arena>>,
259+
local_exprs: LocalExprs<'arena>,
259260
initial_buffer: Buffer<'data>,
260261
pending_formats: Vec<(usize, ArcValue<'arena>)>,
261262
cached_refs: HashMap<usize, Vec<ParsedRef<'arena>>>,
@@ -283,7 +284,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
283284

284285
fn eval_env(&mut self) -> semantics::EvalEnv<'arena, '_> {
285286
let elim_env = semantics::ElimEnv::new(&self.item_exprs, [][..].into());
286-
semantics::EvalEnv::new(elim_env, &mut self.local_exprs)
287+
semantics::EvalEnv::new(elim_env, &mut self.local_exprs).with_mode(EvalMode::Strict)
287288
}
288289

289290
fn elim_env(&self) -> semantics::ElimEnv<'arena, '_> {
@@ -295,7 +296,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
295296
for item in module.items {
296297
match item {
297298
Item::Def { expr, .. } => {
298-
let expr = self.eval_env().eval(expr);
299+
let expr = self.eval_env().delay_or_eval(expr);
299300
self.item_exprs.push(expr);
300301
}
301302
}
@@ -332,7 +333,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
332333
let mut exprs = Vec::with_capacity(formats.len());
333334

334335
while let Some((format, next_formats)) = self.elim_env().split_telescope(formats) {
335-
let expr = self.read_format(reader, &format)?;
336+
let expr = LazyValue::eager(self.read_format(reader, &format)?);
336337
exprs.push(expr.clone());
337338
formats = next_formats(expr);
338339
}
@@ -343,8 +344,10 @@ impl<'arena, 'data> Context<'arena, 'data> {
343344
))
344345
}
345346
Value::FormatCond(_label, format, cond) => {
346-
let value = self.read_format(reader, format)?;
347-
let cond_res = self.elim_env().apply_closure(cond, value.clone());
347+
let value = self.read_format(reader, &self.elim_env().force_lazy(format))?;
348+
let cond_res = self
349+
.elim_env()
350+
.apply_closure(cond, LazyValue::eager(value.clone()));
348351

349352
match cond_res.as_ref() {
350353
Value::ConstLit(Const::Bool(true)) => Ok(value),
@@ -366,7 +369,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
366369
while let Some((format, next_formats)) = self.elim_env().split_telescope(formats) {
367370
let mut reader = reader.clone();
368371

369-
let expr = self.read_format(&mut reader, &format)?;
372+
let expr = LazyValue::eager(self.read_format(&mut reader, &format)?);
370373
exprs.push(expr.clone());
371374
formats = next_formats(expr);
372375

@@ -406,6 +409,8 @@ impl<'arena, 'data> Context<'arena, 'data> {
406409
) -> Result<ArcValue<'arena>, ReadError<'arena>> {
407410
use crate::core::semantics::Elim::FunApp;
408411

412+
let force = |expr| self.elim_env().force_lazy(expr);
413+
409414
match (prim, slice) {
410415
(Prim::FormatU8, []) => read_const(reader, span, read_u8, |num| Const::U8(num, UIntStyle::Decimal)),
411416
(Prim::FormatU16Be, []) => read_const(reader, span, read_u16be, |num| Const::U16(num, UIntStyle::Decimal)),
@@ -425,22 +430,18 @@ impl<'arena, 'data> Context<'arena, 'data> {
425430
(Prim::FormatF32Le, []) => read_const(reader, span, read_f32le, Const::F32),
426431
(Prim::FormatF64Be, []) => read_const(reader, span, read_f64be, Const::F64),
427432
(Prim::FormatF64Le, []) => read_const(reader, span, read_f64le, Const::F64),
428-
(Prim::FormatRepeatLen8, [FunApp(_, len), FunApp(_, format)]) => self.read_repeat_len(reader, span, len, format),
429-
(Prim::FormatRepeatLen16, [FunApp(_, len), FunApp(_, format)]) => self.read_repeat_len(reader, span, len, format),
430-
(Prim::FormatRepeatLen32, [FunApp(_, len), FunApp(_, format)]) => self.read_repeat_len(reader, span, len, format),
431-
(Prim::FormatRepeatLen64, [FunApp(_, len), FunApp(_, format)]) => self.read_repeat_len(reader, span, len, format),
432-
(Prim::FormatRepeatUntilEnd, [FunApp(_,format)]) => self.read_repeat_until_end(reader, format),
433-
(Prim::FormatLimit8, [FunApp(_, limit), FunApp(_, format)]) => self.read_limit(reader, limit, format),
434-
(Prim::FormatLimit16, [FunApp(_, limit), FunApp(_, format)]) => self.read_limit(reader, limit, format),
435-
(Prim::FormatLimit32, [FunApp(_, limit), FunApp(_, format)]) => self.read_limit(reader, limit, format),
436-
(Prim::FormatLimit64, [FunApp(_, limit), FunApp(_, format)]) => self.read_limit(reader, limit, format),
437-
(Prim::FormatLink, [FunApp(_, pos), FunApp(_, format)]) => self.read_link(span, pos, format),
438-
(Prim::FormatDeref, [FunApp(_, format), FunApp(_, r#ref)]) => self.read_deref(format, r#ref),
433+
(Prim::FormatRepeatLen8| Prim::FormatRepeatLen16 | Prim::FormatRepeatLen32 | Prim::FormatRepeatLen64,
434+
[FunApp(_, len), FunApp(_, format)]) => self.read_repeat_len(reader, span, &force(len), &force(format)),
435+
(Prim::FormatRepeatUntilEnd, [FunApp(_,format)]) => self.read_repeat_until_end(reader, &force(format)),
436+
(Prim::FormatLimit8 | Prim::FormatLimit16 | Prim::FormatLimit32 | Prim::FormatLimit64,
437+
[FunApp(_, limit), FunApp(_, format)]) => self.read_limit(reader,&force(limit) , &force(format)),
438+
(Prim::FormatLink, [FunApp(_, pos), FunApp(_, format)]) => self.read_link(span, &force(pos), &force(format)),
439+
(Prim::FormatDeref, [FunApp(_, format), FunApp(_, r#ref)]) => self.read_deref(&force(format), &force(r#ref)),
439440
(Prim::FormatStreamPos, []) => read_stream_pos(reader, span),
440-
(Prim::FormatSucceed, [_, FunApp(_, elem)]) => Ok(elem.clone()),
441+
(Prim::FormatSucceed, [_, FunApp(_, elem)]) => Ok(force(elem)),
441442
(Prim::FormatFail, []) => Err(ReadError::ReadFailFormat(span)),
442-
(Prim::FormatUnwrap, [_, FunApp(_, option)]) => match option.match_prim_spine() {
443-
Some((Prim::OptionSome, [_, FunApp(_, elem)])) => Ok(elem.clone()),
443+
(Prim::FormatUnwrap, [_, FunApp(_, option)]) => match force(option).match_prim_spine() {
444+
Some((Prim::OptionSome, [_, FunApp(_, elem)])) => Ok(force(elem)),
444445
Some((Prim::OptionNone, [_])) => Err(ReadError::UnwrappedNone(span)),
445446
_ => Err(ReadError::InvalidValue(span)),
446447
},
@@ -464,7 +465,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
464465
};
465466

466467
let elem_exprs = (0..len)
467-
.map(|_| self.read_format(reader, elem_format))
468+
.map(|_| (self.read_format(reader, elem_format).map(LazyValue::eager)))
468469
.collect::<Result<_, _>>()?;
469470

470471
Ok(Spanned::new(span, Arc::new(Value::ArrayLit(elem_exprs))))
@@ -481,7 +482,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
481482
loop {
482483
match self.read_format(reader, elem_format) {
483484
Ok(elem) => {
484-
elems.push(elem);
485+
elems.push(LazyValue::eager(elem));
485486
current_offset = reader.relative_offset();
486487
}
487488
Err(ReadError::BufferError(_, BufferError::UnexpectedEndOfBuffer)) => {
@@ -557,7 +558,7 @@ impl<'arena, 'data> Context<'arena, 'data> {
557558
fn lookup_ref<'context>(
558559
&'context self,
559560
pos: usize,
560-
format: &ArcValue<'_>,
561+
format: &ArcValue<'arena>,
561562
) -> Option<&'context ParsedRef<'arena>> {
562563
// NOTE: The number of calls to `semantics::ConversionEnv::is_equal`
563564
// when looking up cached references is a bit of a pain. If this ever

fathom/src/core/prim.rs

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::sync::Arc;
33
use fxhash::FxHashMap;
44
use scoped_arena::Scope;
55

6+
use super::semantics::{LazyValue, LocalExprs};
67
use crate::core::semantics::{ArcValue, Elim, ElimEnv, Head, Value};
78
use crate::core::{self, Const, Plicity, Prim, UIntStyle};
89
use crate::env::{self, SharedEnv, UniqueEnv};
@@ -508,8 +509,8 @@ struct EnvBuilder<'arena> {
508509
entries: FxHashMap<Symbol, (Prim, ArcValue<'arena>)>,
509510
scope: &'arena Scope<'arena>,
510511
meta_exprs: UniqueEnv<Option<ArcValue<'arena>>>,
511-
item_exprs: UniqueEnv<ArcValue<'arena>>,
512-
local_exprs: SharedEnv<ArcValue<'arena>>,
512+
item_exprs: UniqueEnv<LazyValue<'arena>>,
513+
local_exprs: LocalExprs<'arena>,
513514
}
514515

515516
impl<'arena> EnvBuilder<'arena> {
@@ -577,13 +578,13 @@ macro_rules! step {
577578
// TODO: Should we merge the spans of the param idents to produce the body span?
578579
macro_rules! const_step {
579580
([$($param:ident : $Input:ident),*] => $body:expr) => {
580-
step!(_, [$($param),*] => match ($($param.as_ref(),)*) {
581+
step!(env, [$($param),*] => match ($(env.force_lazy($param).as_ref(),)*) {
581582
($(Value::ConstLit(Const::$Input($param, ..)),)*) => Spanned::empty(Arc::new(Value::ConstLit($body))),
582583
_ => return None,
583584
})
584585
};
585586
([$($param:ident , $style:ident : $Input:ident),*] => $body:expr) => {
586-
step!(_, [$($param),*] => match ($($param.as_ref(),)*) {
587+
step!(env, [$($param),*] => match ($(env.force_lazy($param).as_ref(),)*) {
587588
($(Value::ConstLit(Const::$Input($param, $style)),)*) => Spanned::empty(Arc::new(Value::ConstLit($body))),
588589
_ => return None,
589590
})
@@ -611,21 +612,18 @@ pub fn repr(prim: Prim) -> Step {
611612
Prim::FormatF32Le => step!(_, [] => Spanned::empty(Arc::new(Value::prim(Prim::F32Type, [])))),
612613
Prim::FormatF64Be => step!(_, [] => Spanned::empty(Arc::new(Value::prim(Prim::F64Type, [])))),
613614
Prim::FormatF64Le => step!(_, [] => Spanned::empty(Arc::new(Value::prim(Prim::F64Type, [])))),
614-
Prim::FormatRepeatLen8 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array8Type, [len.clone(), env.format_repr(elem)])))),
615-
Prim::FormatRepeatLen16 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array16Type, [len.clone(), env.format_repr(elem)])))),
616-
Prim::FormatRepeatLen32 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array32Type, [len.clone(), env.format_repr(elem)])))),
617-
Prim::FormatRepeatLen64 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array64Type, [len.clone(), env.format_repr(elem)])))),
618-
Prim::FormatLimit8 => step!(env, [_, elem] => env.format_repr(elem)),
619-
Prim::FormatLimit16 => step!(env, [_, elem] => env.format_repr(elem)),
620-
Prim::FormatLimit32 => step!(env, [_, elem] => env.format_repr(elem)),
621-
Prim::FormatLimit64 => step!(env, [_, elem] => env.format_repr(elem)),
622-
Prim::FormatRepeatUntilEnd => step!(env, [elem] => Spanned::empty(Arc::new(Value::prim(Prim::ArrayType, [env.format_repr(elem)])))),
623-
Prim::FormatLink => step!(_, [_, elem] => Spanned::empty(Arc::new(Value::prim(Prim::RefType, [elem.clone()])))),
624-
Prim::FormatDeref => step!(env, [elem, _] => env.format_repr(elem)),
615+
Prim::FormatRepeatLen8 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array8Type, [env.force_lazy(len), env.format_repr(&env.force_lazy(elem))])))),
616+
Prim::FormatRepeatLen16 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array16Type, [env.force_lazy(len), env.format_repr(&env.force_lazy(elem))])))),
617+
Prim::FormatRepeatLen32 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array32Type, [env.force_lazy(len), env.format_repr(&env.force_lazy(elem))])))),
618+
Prim::FormatRepeatLen64 => step!(env, [len, elem] => Spanned::empty(Arc::new(Value::prim(Prim::Array64Type, [env.force_lazy(len), env.format_repr(&env.force_lazy(elem))])))),
619+
Prim::FormatLimit8 | Prim::FormatLimit16 | Prim::FormatLimit32 | Prim::FormatLimit64 => step!(env, [_, elem] => env.format_repr(&env.force_lazy(elem))),
620+
Prim::FormatRepeatUntilEnd => step!(env, [elem] => Spanned::empty(Arc::new(Value::prim(Prim::ArrayType, [env.format_repr(&env.force_lazy(elem))])))),
621+
Prim::FormatLink => step!(env, [_, elem] => Spanned::empty(Arc::new(Value::prim(Prim::RefType, [env.force_lazy(elem)])))),
622+
Prim::FormatDeref => step!(env, [elem, _] => env.format_repr(&env.force_lazy(elem))),
625623
Prim::FormatStreamPos => step!(_, [] => Spanned::empty(Arc::new(Value::prim(Prim::PosType, [])))),
626-
Prim::FormatSucceed => step!(_, [elem, _] => elem.clone()),
624+
Prim::FormatSucceed => step!(env, [elem, _] => env.force_lazy(elem)),
627625
Prim::FormatFail => step!(_, [] => Spanned::empty(Arc::new(Value::prim(Prim::VoidType, [])))),
628-
Prim::FormatUnwrap => step!(_, [elem, _] => elem.clone()),
626+
Prim::FormatUnwrap => step!(env, [elem, _] => env.force_lazy(elem)),
629627
Prim::ReportedError => step!(_, [] => Spanned::empty(Arc::new(Value::prim(Prim::ReportedError, [])))),
630628
_ => |_, _| None,
631629
}
@@ -641,15 +639,49 @@ pub fn step(prim: Prim) -> Step {
641639
#[allow(unreachable_code)]
642640
Prim::Absurd => step!(_, [_, _] => panic!("Constructed an element of `Void`")),
643641

644-
Prim::FormatRepr => step!(env, [format] => env.format_repr(format)),
642+
Prim::FormatRepr => step!(env, [format] => env.format_repr(&env.force_lazy(format))),
645643

646644
Prim::BoolEq => const_step!([x: Bool, y: Bool] => Const::Bool(x == y)),
647645
Prim::BoolNeq => const_step!([x: Bool, y: Bool] => Const::Bool(x != y)),
648646
Prim::BoolNot => const_step!([x: Bool] => Const::Bool(bool::not(*x))),
649-
Prim::BoolAnd => const_step!([x: Bool, y: Bool] => Const::Bool(*x && *y)),
650-
Prim::BoolOr => const_step!([x: Bool, y: Bool] => Const::Bool(*x || *y)),
651647
Prim::BoolXor => const_step!([x: Bool, y: Bool] => Const::Bool(*x ^ *y)),
652648

649+
Prim::BoolAnd => |env: &ElimEnv, spine: &[Elim]| match spine {
650+
[Elim::FunApp(_,x), Elim::FunApp(_, y)] => {
651+
let x = env.force_lazy(x);
652+
match x.as_ref() {
653+
Value::ConstLit(Const::Bool(false)) => Some(x),
654+
Value::ConstLit(Const::Bool(true)) => {
655+
let y = env.force_lazy(y);
656+
match y.as_ref() {
657+
Value::ConstLit(Const::Bool(_)) => Some(y),
658+
_ => None,
659+
}
660+
}
661+
_ => None,
662+
}
663+
}
664+
_ => None,
665+
},
666+
667+
Prim::BoolOr => |env: &ElimEnv, spine: &[Elim]| match spine {
668+
[Elim::FunApp(_,x), Elim::FunApp(_, y)] => {
669+
let x = env.force_lazy(x);
670+
match x.as_ref() {
671+
Value::ConstLit(Const::Bool(true)) => Some(x),
672+
Value::ConstLit(Const::Bool(false)) => {
673+
let y = env.force_lazy(y);
674+
match y.as_ref() {
675+
Value::ConstLit(Const::Bool(_)) => Some(y),
676+
_ => None,
677+
}
678+
}
679+
_ => None,
680+
}
681+
}
682+
_ => None,
683+
},
684+
653685
Prim::U8Eq => const_step!([x: U8, y: U8] => Const::Bool(x == y)),
654686
Prim::U8Neq => const_step!([x: U8, y: U8] => Const::Bool(x != y)),
655687
Prim::U8Gt => const_step!([x: U8, y: U8] => Const::Bool(x > y)),
@@ -775,22 +807,20 @@ pub fn step(prim: Prim) -> Step {
775807
Prim::S64UAbs => const_step!([x: S64] => Const::U64(i64::unsigned_abs(*x), UIntStyle::Decimal)),
776808

777809
Prim::OptionFold => step!(env, [_, _, on_none, on_some, option] => {
778-
match option.match_prim_spine()? {
810+
match env.force_lazy(option).match_prim_spine()? {
779811
(Prim::OptionSome, [_, Elim::FunApp(Plicity::Explicit, value)]) => {
780-
env.fun_app(Plicity::Explicit, on_some.clone(), value.clone())
812+
env.fun_app(Plicity::Explicit, env.force_lazy(on_some), value)
781813
},
782-
(Prim::OptionNone, [_]) => on_none.clone(),
814+
(Prim::OptionNone, [_]) => env.force_lazy(on_none),
783815
_ => return None,
784816
}
785817
}),
786818

787819
Prim::Array8Find | Prim::Array16Find | Prim::Array32Find | Prim::Array64Find => {
788-
step!(env, [_, elem_type, pred, array] => match array.as_ref() {
820+
step!(env, [_, elem_type, pred, array] => match env.force_lazy(array).as_ref() {
789821
Value::ArrayLit(elems) => {
790822
for elem in elems {
791-
match env.fun_app(
792-
Plicity::Explicit,
793-
pred.clone(), elem.clone()).as_ref() {
823+
match env.fun_app(Plicity::Explicit, env.force_lazy(pred), elem).as_ref() {
794824
Value::ConstLit(Const::Bool(true)) => {
795825
return Some(Spanned::empty(Arc::new(Value::Stuck(
796826
Head::Prim(Prim::OptionSome),
@@ -814,16 +844,16 @@ pub fn step(prim: Prim) -> Step {
814844
}
815845

816846
Prim::Array8Index | Prim::Array16Index | Prim::Array32Index | Prim::Array64Index => {
817-
step!(_, [_, _, index, array] => match array.as_ref() {
847+
step!(env, [_, _, index, array] => match env.force_lazy(array).as_ref() {
818848
Value::ArrayLit(elems) => {
819-
let index = match (index).as_ref() {
849+
let index = match env.force_lazy(index).as_ref() {
820850
Value::ConstLit(Const::U8(index, _)) => Some(usize::from(*index)),
821851
Value::ConstLit(Const::U16(index, _)) => Some(usize::from(*index)),
822852
Value::ConstLit(Const::U32(index, _)) => usize::try_from(*index).ok(),
823853
Value::ConstLit(Const::U64(index, _)) => usize::try_from(*index).ok(),
824854
_ => return None,
825855
}?;
826-
elems.get(index).cloned()?
856+
env.force_lazy(elems.get(index)?)
827857
}
828858
_ => return None,
829859
})

0 commit comments

Comments
 (0)