Invert event loop
This commit is contained in:
@@ -29,6 +29,10 @@ pub type Place = (usize, usize);
|
||||
/// The call place of the entry fn, which the host calls
|
||||
pub const HOST: Place = (usize::MAX, 0);
|
||||
|
||||
/// The call place of the fn that the host calls when an IO op completes (see
|
||||
/// `Code::HostLink`)
|
||||
pub const HOST_COMPLETE: Place = (usize::MAX, 1);
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct InferRequest {
|
||||
pub fn_id: usize,
|
||||
@@ -60,6 +64,7 @@ pub struct TypeCache {
|
||||
objects: BTreeMap<(usize, usize, Place), Cell>, // the cell of each name: the fn and instr that make the objects, and the call place
|
||||
builtins: Vec<Cell>, // the cells of the natives, then of the proto links
|
||||
pub protos: Protos, // the prototype of each `ProtoOf`, as the stdlib links it
|
||||
pub host_complete: Type, // what the host calls when an IO op completes, as the stdlib links it
|
||||
version: usize, // goes up on every change of a cell, a return or a proto, and on every new cell or walk
|
||||
}
|
||||
|
||||
@@ -83,6 +88,7 @@ impl TypeCache {
|
||||
match code {
|
||||
Code::Native(id) => &self.builtins[id],
|
||||
Code::ProtoLink(kind) => &self.builtins[NATIVES.len() + kind as usize],
|
||||
Code::HostLink => &self.builtins[NATIVES.len() + ProtoOf::ALL.len()],
|
||||
Code::Fn(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -184,6 +190,28 @@ fn call_code(cache: &mut TypeCache, code: Code, arg_types: &[Type], fns: &[RegFn
|
||||
cache.protos[kind as usize] = joined;
|
||||
Type::Undefined
|
||||
}
|
||||
Code::HostLink => {
|
||||
let joined = join(&cache.host_complete, args.first().unwrap_or(&Type::Undefined));
|
||||
cache.changed(joined != cache.host_complete);
|
||||
cache.host_complete = joined;
|
||||
Type::Undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The calls that the host makes: the entry, with no args, then the fn that
|
||||
/// it calls when an IO op completes, with the op's handle. Each member of its
|
||||
/// type is its own env, and `this` is undefined
|
||||
fn host_calls(cache: &mut TypeCache, fns: &[RegFn]) {
|
||||
// The synthetic program entry is appended last by `flatten`
|
||||
cache.call(fns.len() - 1, HOST, &[], fns);
|
||||
|
||||
for member in cache.host_complete.clone().members() {
|
||||
if let Type::Obj(cell) = member
|
||||
&& let Some(Code::Fn(fn_id)) = cell.code()
|
||||
{
|
||||
cache.call(fn_id, HOST_COMPLETE, &[member.clone(), Type::Undefined, Type::Int], fns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,19 +234,18 @@ pub fn infer_types(fns: &[RegFn]) -> TypeCache {
|
||||
objects: BTreeMap::new(),
|
||||
builtins: vec![],
|
||||
protos: std::array::from_fn(|_| Type::Unknown),
|
||||
host_complete: Type::Unknown,
|
||||
version: 0,
|
||||
};
|
||||
|
||||
let codes = (0..NATIVES.len()).map(Code::Native).chain(ProtoOf::ALL.map(Code::ProtoLink));
|
||||
let codes = (0..NATIVES.len()).map(Code::Native).chain(ProtoOf::ALL.map(Code::ProtoLink)).chain([Code::HostLink]);
|
||||
cache.builtins = codes.map(|code| Cell::new(ObjKind::Fn(code))).collect();
|
||||
|
||||
loop {
|
||||
let version = cache.version;
|
||||
cache.walks.iter_mut().for_each(|w| w.result = None);
|
||||
|
||||
// The synthetic program entry is appended last by `flatten`. It is
|
||||
// called by the host with no args
|
||||
cache.call(fns.len() - 1, HOST, &[], fns);
|
||||
host_calls(&mut cache, fns);
|
||||
|
||||
if cache.version == version {
|
||||
return cache;
|
||||
@@ -302,6 +329,7 @@ fn walk_fn(w: usize, reg_fns: &[RegFn], cache: &mut TypeCache) -> InferResult {
|
||||
JsValue::Undefined => Type::Undefined,
|
||||
JsValue::NativeFn(id) => Type::Obj(cache.builtin(Code::Native(id)).clone()),
|
||||
JsValue::ProtoLink(kind) => Type::Obj(cache.builtin(Code::ProtoLink(kind)).clone()),
|
||||
JsValue::HostLink => Type::Obj(cache.builtin(Code::HostLink).clone()),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user