Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
yannham committed Aug 5, 2024
1 parent b3c8e30 commit 3ebd738
Show file tree
Hide file tree
Showing 16 changed files with 278 additions and 157 deletions.
47 changes: 47 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,53 @@ use std::process::ExitCode;
use crate::cli::{Command, Options};

fn main() -> ExitCode {
// Show the size of the Term structure
println!(
"Size of Term: {}",
std::mem::size_of::<nickel_lang_core::term::Term>()
);
println!(
"Size of Label: {}",
std::mem::size_of::<nickel_lang_core::label::Label>()
);
println!(
"Size of Label: {}",
std::mem::size_of::<nickel_lang_core::label::Label>()
);
println!(
"Size of RecordData: {}",
std::mem::size_of::<nickel_lang_core::term::record::RecordData>()
);

println!(
"Size of UnaryOp: {}",
std::mem::size_of::<nickel_lang_core::term::UnaryOp>()
);
println!(
"Size of BinaryOp: {}",
std::mem::size_of::<nickel_lang_core::term::BinaryOp>()
);
println!(
"Size of NAryOp: {}",
std::mem::size_of::<nickel_lang_core::term::NAryOp>()
);
println!(
"Size of TypeAnnotation: {}",
std::mem::size_of::<nickel_lang_core::term::TypeAnnotation>()
);
println!(
"Size of Type: {}",
std::mem::size_of::<nickel_lang_core::typ::Type>()
);
println!(
"Size of ParseError: {}",
std::mem::size_of::<nickel_lang_core::error::ParseError>()
);
println!(
"Size of EvalError: {}",
std::mem::size_of::<nickel_lang_core::error::EvalError>()
);

#[cfg(feature = "metrics")]
let metrics = metrics::Recorder::install();

Expand Down
5 changes: 3 additions & 2 deletions core/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::position::TermPos;
use crate::program::FieldPath;
use crate::stdlib::{self as nickel_stdlib, StdlibModule};
use crate::term::array::Array;
use crate::term::record::{Field, RecordData};
use crate::term::record::Field;
use crate::term::{RichTerm, SharedTerm, Term};
use crate::transform::import_resolution;
use crate::typ::UnboundTypeVariableError;
Expand Down Expand Up @@ -697,7 +697,8 @@ impl Cache {

if state < EntryState::Transforming {
match SharedTerm::make_mut(&mut term.term) {
Term::Record(RecordData { ref mut fields, .. }) => {
Term::Record(ref mut data) => {
let fields = &mut data.fields;
let map_res: Result<_, UnboundTypeVariableError> =
std::mem::take(fields)
.into_iter()
Expand Down
4 changes: 2 additions & 2 deletions core/src/eval/fixpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn rec_env<'a, I: Iterator<Item = (&'a LocIdent, &'a Field)>, C: Cache>(
};

let closure = Closure {
body: RichTerm::from(Term::RuntimeError(error)),
body: RichTerm::from(Term::RuntimeError(Box::new(error))),
env: Environment::new(),
};

Expand Down Expand Up @@ -164,5 +164,5 @@ pub fn revert<C: Cache>(cache: &mut C, record_data: RecordData) -> Term {

// At run-time, we don't care about `RecordDeps`, because this information is already stored in
// the cache (thunks in call-by-need mode). We set it to `None`.
Term::RecRecord(record_data, Vec::new(), None)
Term::RecRecord(Box::new(record_data), Vec::new(), None)
}
12 changes: 8 additions & 4 deletions core/src/eval/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,11 @@ pub fn merge<C: Cache>(
// exactly the same, but can't be shadowed.
let eq_contract = mk_app!(stdlib::internals::stdlib_contract_equal(), t1);
let result = mk_app!(
mk_term::op2(BinaryOp::ContractApply, eq_contract, Term::Lbl(label)),
mk_term::op2(
BinaryOp::ContractApply,
eq_contract,
Term::Lbl(Box::new(label))
),
t2
)
.with_pos(pos_op);
Expand Down Expand Up @@ -289,7 +293,7 @@ pub fn merge<C: Cache>(
// of raising a blame error as for a delayed contract error, which can't be
// caught in user-code, we return an `'Error {..}` value instead.
return Ok(Closure::atomic_closure(
mk_term::enum_variant("Error", Term::Record(RecordData::with_field_values([
mk_term::enum_variant("Error", Term::Record(Box::new(RecordData::with_field_values([
("message".into(), mk_term::string(format!("extra field{plural} {fields_list}"))),
("notes".into(), Term::Array([
mk_term::string("Have you misspelled a field?"),
Expand All @@ -300,7 +304,7 @@ pub fn merge<C: Cache>(
`{some_field | SomeContract, ..}`, to make it accept extra fields."
),
].into_iter().collect(), Default::default()).into())
])))));
]))))));
}
_ => (),
};
Expand Down Expand Up @@ -359,7 +363,7 @@ pub fn merge<C: Cache>(
// of program transformations. At this point, the interpreter doesn't care
// about them anymore, and dependencies are stored at the level of revertible
// cache elements directly.
Term::RecRecord(RecordData::new(m, attrs, None), Vec::new(), None),
Term::RecRecord(Box::new(RecordData::new(m, attrs, None)), Vec::new(), None),
final_pos,
),
env: Environment::new(),
Expand Down
75 changes: 47 additions & 28 deletions core/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
//! probably suboptimal for a functional language and is unable to collect cyclic data, which may
//! appear inside recursive records. A dedicated garbage collector is probably something to
//! consider at some point.
use crate::term::RecordInsertData;
use crate::{
cache::{Cache as ImportCache, Envs, ImportResolver},
closurize::{closurize_rec_record, Closurize},
Expand Down Expand Up @@ -446,25 +447,37 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
// a definition, we complete the error with the additional information of where
// it was accessed:
let Closure { body, env } = self.cache.get(idx);
let body = match_sharedterm!(match (body.term) {
Term::RuntimeError(EvalError::MissingFieldDef {
id,
metadata,
pos_record,
pos_access: TermPos::None,
}) => RichTerm::new(
Term::RuntimeError(EvalError::MissingFieldDef {

let body = match body.term.as_ref() {
Term::RuntimeError(error) if matches!(**error, EvalError::MissingFieldDef { .. }) => {
let term = body.term.into_owned();
// unreachable(): we checked in the pattern that we are precisely in this case
let Term::RuntimeError(error) = term else {
unreachable!();
};
// unreachable(): we checked in the pattern that we are precisely in this case
let EvalError::MissingFieldDef {
id,
metadata,
pos_record,
pos_access: pos,
}),
pos,
),
_ => {
body
pos_access: TermPos::None,
} = *error
else {
unreachable!()
};

RichTerm::new(
Term::RuntimeError(Box::new(EvalError::MissingFieldDef {
id,
metadata,
pos_record,
pos_access: pos,
})),
pos,
)
}
});
_ => body,
};

Ok(Closure { body, env })
}
Expand Down Expand Up @@ -541,7 +554,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
// This operation should not be allowed to evaluate a sealed term
return Err(EvalError::BlameError {
evaluated_arg: label.get_evaluated_arg(&self.cache),
label,
label: *label,
call_stack: self.call_stack.clone(),
});
}
Expand Down Expand Up @@ -688,7 +701,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
Term::Record(data) if !data.attrs.closurized => {
Closure {
body: RichTerm::new(
Term::Record(data.closurize(&mut self.cache, env)),
Term::Record(Box::new(data.closurize(&mut self.cache, env))),
pos,
),
env: Environment::new(),
Expand All @@ -704,9 +717,15 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
// type, once we have a different representation for runtime evaluation,
// instead of relying on invariants. But for now, we have to live with it.
let (mut static_part, dyn_fields) = if !data.attrs.closurized {
closurize_rec_record(&mut self.cache, data, dyn_fields, deps, env)
closurize_rec_record(
&mut self.cache,
*data,
dyn_fields,
deps.map(|deps| *deps),
env,
)
} else {
(data, dyn_fields)
(*data, dyn_fields)
};

let rec_env =
Expand All @@ -733,7 +752,7 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
// recursive environment only contains the static fields, and not the dynamic
// fields.
let extended = dyn_fields.into_iter().fold(
RichTerm::new(Term::Record(static_part), pos),
RichTerm::new(Term::Record(Box::new(static_part)), pos),
|acc, (name_as_term, mut field)| {
let pos = field
.value
Expand All @@ -751,12 +770,12 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
} = field;

let extend = mk_term::op2(
BinaryOp::RecordInsert {
BinaryOp::RecordInsert(Box::new(RecordInsertData {
metadata,
pending_contracts,
ext_kind,
op_kind: RecordOpKind::ConsiderAllFields,
},
})),
name_as_term,
acc,
);
Expand Down Expand Up @@ -828,10 +847,10 @@ impl<R: ImportResolver, C: Cache> VirtualMachine<R, C> {
}
}
Term::ParseError(parse_error) => {
return Err(EvalError::ParseError(parse_error));
return Err(EvalError::ParseError(*parse_error));
}
Term::RuntimeError(error) => {
return Err(error);
return Err(*error);
}
// For now, we simply erase annotations at runtime. They aren't accessible anyway
// (as opposed to field metadata) and don't change the operational semantics, as
Expand Down Expand Up @@ -1226,8 +1245,8 @@ pub fn subst<C: Cache>(
let t = subst(cache, t, initial_env, env);
RichTerm::new(Term::Sealed(i, t, lbl), pos)
}
Term::Record(record) => {
let mut record = record
Term::Record(mut record) => {
*record = record
.map_defined_values(|_, value| subst(cache, value, initial_env, env));

// [^subst-closurized-false]: After substitution, there's no closure in here anymore.
Expand All @@ -1239,8 +1258,8 @@ pub fn subst<C: Cache>(

RichTerm::new(Term::Record(record), pos)
}
Term::RecRecord(record, dyn_fields, deps) => {
let mut record = record
Term::RecRecord(mut record, dyn_fields, deps) => {
*record = record
.map_defined_values(|_, value| subst(cache, value, initial_env, env));

// see [^subst-closurized-false]
Expand Down
Loading

0 comments on commit 3ebd738

Please sign in to comment.