First declosure impl

This commit is contained in:
2026-09-04 13:53:59 +00:00
parent af85244587
commit 617dbeb988
7 changed files with 376 additions and 11 deletions
+28 -1
View File
@@ -10,6 +10,9 @@
//! `get_field "prototype" ; put_field @meth`; the field-initialiser tail is
//! dropped. Detection (`find_class_seqs`) records the ranges; replacement
//! (`ClassSequence::emit_prototype`) reads operands out of each matched range.
//!
//! Derived classes (`extends`) are unsupported and panic: prototype form would
//! have to flatten the parent's prototype in and lower `super`.
use std::range::Range;
@@ -160,6 +163,16 @@ fn find_class_seqs(mut ins: &[RegInstr]) -> Vec<ClassSequence> {
fn match_class_seq(ins: &[RegInstr]) -> Result<(&[RegInstr], usize), &[RegInstr]> {
let ins = match_one(ins, |i| i.op == OpCode::PushConst8)?;
// A class build is `push_const8 ; define_class`. Derived classes (`extends`)
// are unsupported: prototype form would have to flatten the parent's
// prototype in and lower `super`, neither of which is implemented.
if let Some(i) = ins.first() {
if i.op == OpCode::DefineClass && is_derived(i) {
panic!("declass: derived classes (extends) are not supported");
}
}
let ins = match_one(ins, |i| i.op == OpCode::DefineClass)?;
let (ins, num_methods) = match_many(ins, match_method_seq);
let ins = match_opt(ins, match_field_init_seq);
@@ -167,6 +180,15 @@ fn match_class_seq(ins: &[RegInstr]) -> Result<(&[RegInstr], usize), &[RegInstr]
Ok((ins, num_methods))
}
/// A derived class: `define_class` with the derived flag set.
fn is_derived(i: &RegInstr) -> bool {
matches!(i.imm, ImmOperand::AtomU8 { arg, .. } if arg & 1 == 1)
}
// TODO: accessors are not handled. A getter/setter is a `define_method` with a
// non-zero kind in `arg`; this matcher takes it for an ordinary method, so it
// is wrongly lowered to a `put_field` (a data property) instead of an accessor
// property. It should instead make the whole class pass through untouched.
fn match_method_seq(ins: &[RegInstr]) -> Result<&[RegInstr], &[RegInstr]> {
let ins = match_one(ins, |i| i.op == OpCode::Fclosure8)?;
let ins = match_one(ins, |i| i.op == OpCode::DefineMethod)?;
@@ -177,7 +199,12 @@ fn match_field_init_seq(ins: &[RegInstr]) -> Result<&[RegInstr], &[RegInstr]> {
let is_put_loc = |op| {
matches!(
op,
OpCode::PutLoc | OpCode::PutLoc0 | OpCode::PutLoc1 | OpCode::PutLoc2 | OpCode::PutLoc3
OpCode::PutLoc
| OpCode::PutLoc8
| OpCode::PutLoc0
| OpCode::PutLoc1
| OpCode::PutLoc2
| OpCode::PutLoc3
)
};