implement Select and HasAttr
This commit is contained in:
+53
-15
@@ -47,8 +47,13 @@ pub enum Op {
|
||||
MakeEmptyAttrs,
|
||||
SelectStatic,
|
||||
SelectDynamic,
|
||||
HasAttrPathStatic,
|
||||
HasAttrPathDynamic,
|
||||
HasAttrStatic,
|
||||
HasAttrDynamic,
|
||||
HasAttrResolve,
|
||||
JumpIfSelectSucceeded,
|
||||
HasAttr,
|
||||
JumpIfSelectFailed,
|
||||
|
||||
MakeList,
|
||||
MakeEmptyList,
|
||||
@@ -822,6 +827,7 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
||||
) {
|
||||
self.emit_expr(expr);
|
||||
|
||||
let mut dynamic_patches = Vec::new();
|
||||
for attr in attrpath.iter() {
|
||||
match *attr {
|
||||
Attr::Str(sym, _) => {
|
||||
@@ -831,6 +837,8 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
||||
self.emit_str_id(sym);
|
||||
}
|
||||
Attr::Dynamic(key_expr, _) => {
|
||||
self.emit_op(Op::JumpIfSelectFailed);
|
||||
dynamic_patches.push(self.emit_i32_placeholder());
|
||||
self.emit_expr(key_expr);
|
||||
let span_id = self.ctx.register_span(span);
|
||||
self.emit_op(Op::SelectDynamic);
|
||||
@@ -840,35 +848,65 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> {
|
||||
}
|
||||
|
||||
if let Some(default) = default {
|
||||
let before: i32 = self.ctx.get_code().len().try_into().unwrap();
|
||||
for patch in dynamic_patches {
|
||||
self.patch_jump_target(patch);
|
||||
}
|
||||
self.emit_op(Op::JumpIfSelectSucceeded);
|
||||
let placeholder = self.emit_i32_placeholder();
|
||||
let before: i32 = self.ctx.get_code().len().try_into().unwrap();
|
||||
self.emit_expr(default);
|
||||
let after: i32 = self.ctx.get_code().len().try_into().unwrap();
|
||||
self.patch_i32(placeholder, after - before);
|
||||
// Offset is relative to after the placeholder, so subtract the
|
||||
// size of JumpIfSelectSucceeded (1) + placeholder (4).
|
||||
self.patch_i32(placeholder, after - before - 5);
|
||||
} else {
|
||||
for patch in dynamic_patches {
|
||||
self.patch_jump_target(patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_has_attr(&mut self, lhs: RawIrRef<'_>, rhs: &[Attr<RawIrRef<'_>>]) {
|
||||
self.emit_expr(lhs);
|
||||
for attr in rhs.iter() {
|
||||
if let Attr::Dynamic(expr, _) = *attr {
|
||||
self.emit_expr(expr);
|
||||
}
|
||||
}
|
||||
self.emit_op(Op::HasAttr);
|
||||
self.emit_u16(rhs.len() as u16);
|
||||
for attr in rhs.iter() {
|
||||
|
||||
let mut dynamic_patches = Vec::new();
|
||||
let [attrs @ .., last] = rhs else {
|
||||
panic!("attrpath is empty");
|
||||
};
|
||||
for attr in attrs {
|
||||
match *attr {
|
||||
Attr::Str(sym, _) => {
|
||||
self.emit_u8(AttrKeyType::Static as u8);
|
||||
Attr::Str(sym, span) => {
|
||||
let span_id = self.ctx.register_span(span);
|
||||
self.emit_op(Op::HasAttrPathStatic);
|
||||
self.emit_u32(span_id);
|
||||
self.emit_str_id(sym);
|
||||
}
|
||||
Attr::Dynamic(_, _) => {
|
||||
self.emit_u8(AttrKeyType::Dynamic as u8);
|
||||
Attr::Dynamic(key_expr, span) => {
|
||||
self.emit_op(Op::JumpIfSelectFailed);
|
||||
dynamic_patches.push(self.emit_i32_placeholder());
|
||||
self.emit_expr(key_expr);
|
||||
let span_id = self.ctx.register_span(span);
|
||||
self.emit_op(Op::HasAttrPathDynamic);
|
||||
self.emit_u32(span_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
match *last {
|
||||
Attr::Str(sym, _) => {
|
||||
self.emit_op(Op::HasAttrStatic);
|
||||
self.emit_str_id(sym);
|
||||
}
|
||||
Attr::Dynamic(key_expr, _) => {
|
||||
self.emit_op(Op::JumpIfSelectFailed);
|
||||
dynamic_patches.push(self.emit_i32_placeholder());
|
||||
self.emit_expr(key_expr);
|
||||
self.emit_op(Op::HasAttrDynamic);
|
||||
}
|
||||
}
|
||||
for patch in dynamic_patches {
|
||||
self.patch_jump_target(patch);
|
||||
}
|
||||
self.emit_op(Op::HasAttrResolve);
|
||||
}
|
||||
|
||||
fn emit_with(
|
||||
|
||||
Reference in New Issue
Block a user