implement foldl'
This commit is contained in:
@@ -171,6 +171,10 @@ pub enum PrimOpPhase {
|
|||||||
FindFile,
|
FindFile,
|
||||||
Floor,
|
Floor,
|
||||||
FoldlStrict,
|
FoldlStrict,
|
||||||
|
FoldlStrictEmpty,
|
||||||
|
FoldlStrictCall1,
|
||||||
|
FoldlStrictCall2,
|
||||||
|
FoldlStrictUpdate,
|
||||||
FromJSON,
|
FromJSON,
|
||||||
FromTOML,
|
FromTOML,
|
||||||
FunctionArgs,
|
FunctionArgs,
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ impl<'gc> crate::Vm<'gc> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let Some(attrs) = scope.as_gc::<AttrSet>() else {
|
let Some(attrs) = scope.as_gc::<AttrSet>() else {
|
||||||
return self.finish_err(Error::eval_error(
|
return self.finish_err(Error::eval_error("internal: scope slot is not an attrset"));
|
||||||
"internal: scope slot is not an attrset",
|
|
||||||
));
|
|
||||||
};
|
};
|
||||||
match attrs.lookup(name) {
|
match attrs.lookup(name) {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
@@ -152,8 +150,8 @@ fn resolve_path_str(current_dir: &str, path: &str) -> Result<String, Box<Error>>
|
|||||||
return Ok(path.to_owned());
|
return Ok(path.to_owned());
|
||||||
} else if let Some(rest) = path.strip_prefix("~/") {
|
} else if let Some(rest) = path.strip_prefix("~/") {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let mut dir = std::env::home_dir()
|
let mut dir =
|
||||||
.ok_or_else(|| Error::eval_error("home dir not defined"))?;
|
std::env::home_dir().ok_or_else(|| Error::eval_error("home dir not defined"))?;
|
||||||
dir.push(rest);
|
dir.push(rest);
|
||||||
dir
|
dir
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -70,4 +70,100 @@ impl<'gc> Vm<'gc> {
|
|||||||
reader.set_pc(PrimOpPhase::FilterCallPred.ip() as usize);
|
reader.set_pc(PrimOpPhase::FilterCallPred.ip() as usize);
|
||||||
Step::Continue(())
|
Step::Continue(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// foldl' op nul list
|
||||||
|
//
|
||||||
|
// Stack layouts across phases:
|
||||||
|
// Entry: [op, nul, list]
|
||||||
|
// Empty: [op, nul]
|
||||||
|
// Call1: [op, list, idx, acc]
|
||||||
|
// Call2: [op, list, idx, acc, intermediate]
|
||||||
|
// Update: [op, list, idx, acc, result]
|
||||||
|
pub(crate) fn primop_foldl_strict_entry(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
self.force_slot(0, reader, mc)?;
|
||||||
|
let list_val = self.peek_forced(0);
|
||||||
|
let Some(list) = list_val.as_gc::<List>() else {
|
||||||
|
return self.finish_type_err(NixType::List, list_val.ty());
|
||||||
|
};
|
||||||
|
if list.inner.borrow().is_empty() {
|
||||||
|
let _ = self.pop(); // list
|
||||||
|
reader.set_pc(PrimOpPhase::FoldlStrictEmpty.ip() as usize);
|
||||||
|
return Step::Continue(());
|
||||||
|
}
|
||||||
|
let list_val = self.pop();
|
||||||
|
let nul_val = self.pop();
|
||||||
|
self.push(list_val);
|
||||||
|
self.push(Value::new_inline(0i32));
|
||||||
|
self.push(nul_val);
|
||||||
|
reader.set_pc(PrimOpPhase::FoldlStrictCall1.ip() as usize);
|
||||||
|
Step::Continue(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn primop_foldl_strict_empty(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
let nul = self.force_and_retry::<StrictValue>(reader, mc)?;
|
||||||
|
let _ = self.pop(); // op
|
||||||
|
self.return_from_primop(nul.relax(), reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn primop_foldl_strict_call1(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
self.force_slot(3, reader, mc)?;
|
||||||
|
let op = self.peek_forced(3);
|
||||||
|
let acc = self.peek(0);
|
||||||
|
self.push(op.relax());
|
||||||
|
self.call(reader, mc, acc, PrimOpPhase::FoldlStrictCall2.ip() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn primop_foldl_strict_call2(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
let idx = self.peek(2).as_inline::<i32>().unwrap();
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
let list = self.peek_forced(3).as_gc::<List>().unwrap();
|
||||||
|
let elem = list.inner.borrow()[idx as usize];
|
||||||
|
self.call(
|
||||||
|
reader,
|
||||||
|
mc,
|
||||||
|
elem,
|
||||||
|
PrimOpPhase::FoldlStrictUpdate.ip() as usize,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn primop_foldl_strict_update(
|
||||||
|
&mut self,
|
||||||
|
reader: &mut BytecodeReader<'_>,
|
||||||
|
_mc: &Mutation<'gc>,
|
||||||
|
) -> Step {
|
||||||
|
let result = self.pop();
|
||||||
|
self.replace(0, result);
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
let idx = self.peek(1).as_inline::<i32>().unwrap();
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
let list = self.peek_forced(2).as_gc::<List>().unwrap();
|
||||||
|
let len = list.inner.borrow().len();
|
||||||
|
if (idx as usize) + 1 == len {
|
||||||
|
let acc = self.pop();
|
||||||
|
let _ = self.pop(); // idx
|
||||||
|
let _ = self.pop(); // list
|
||||||
|
let _ = self.pop(); // op
|
||||||
|
return self.return_from_primop(acc, reader);
|
||||||
|
}
|
||||||
|
self.replace(1, Value::new_inline(idx + 1));
|
||||||
|
reader.set_pc(PrimOpPhase::FoldlStrictCall1.ip() as usize);
|
||||||
|
Step::Continue(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ impl<'gc> Vm<'gc> {
|
|||||||
FilterCallPred => self.primop_filter_call_pred(reader, mc),
|
FilterCallPred => self.primop_filter_call_pred(reader, mc),
|
||||||
FilterCheck => self.primop_filter_check(reader, mc),
|
FilterCheck => self.primop_filter_check(reader, mc),
|
||||||
|
|
||||||
|
FoldlStrict => self.primop_foldl_strict_entry(reader, mc),
|
||||||
|
FoldlStrictEmpty => self.primop_foldl_strict_empty(reader, mc),
|
||||||
|
FoldlStrictCall1 => self.primop_foldl_strict_call1(reader, mc),
|
||||||
|
FoldlStrictCall2 => self.primop_foldl_strict_call2(reader, mc),
|
||||||
|
FoldlStrictUpdate => self.primop_foldl_strict_update(reader, mc),
|
||||||
|
|
||||||
ForceResultShallow => self.primop_force_result_shallow(ctx, reader, mc),
|
ForceResultShallow => self.primop_force_result_shallow(ctx, reader, mc),
|
||||||
ForceResultShallowPush => self.primop_force_result_shallow_push(ctx, reader, mc),
|
ForceResultShallowPush => self.primop_force_result_shallow_push(ctx, reader, mc),
|
||||||
ForceResultShallowLoop => self.primop_force_result_shallow_loop(reader, mc),
|
ForceResultShallowLoop => self.primop_force_result_shallow_loop(reader, mc),
|
||||||
|
|||||||
+4
-1
@@ -636,7 +636,10 @@ enum Scope<'ctx, 'id, 'ir> {
|
|||||||
slot_id: u32,
|
slot_id: u32,
|
||||||
},
|
},
|
||||||
Let(HashMap<StringId, GhostMaybeThunkRef<'id, 'ir>>),
|
Let(HashMap<StringId, GhostMaybeThunkRef<'id, 'ir>>),
|
||||||
Param { sym: StringId, abs_layer: u8 },
|
Param {
|
||||||
|
sym: StringId,
|
||||||
|
abs_layer: u8,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ExtraScope<'ctx> {
|
pub enum ExtraScope<'ctx> {
|
||||||
|
|||||||
Reference in New Issue
Block a user