use crate::dump::DumpContext;
use crate::instruction_definitions::{Reg, Kst, RK, Upvalue};
use crate::view::{ViewOrRegOrKst, ViewOrReg};
use crate::ViewBuilder;
#[derive(Debug, Clone)]
pub struct AssignmentInfo {
pub lhs: AssignmentLHS,
pub sources: Vec<ViewOrRegOrKst>,
pub allocated_local: bool,
}
impl AssignmentInfo {
pub fn dump(&self, context: &mut dyn DumpContext) {
match &self.lhs {
&AssignmentLHS::Partial(ref p) => Self::format_partial_lhs(context, &p),
&AssignmentLHS::Full(ref f) => Self::format_full_lhs(context, &f),
}
context.write_str(" = ");
for (i, src) in self.sources.iter().rev().enumerate() {
if i != 0 {
context.write_str(", ");
}
src.dump(context);
}
}
fn format_partial_lhs(context: &mut dyn DumpContext, partial: &Vec<PartialAssignmentLHS>) {
for (i, p) in partial.iter().rev().enumerate() {
if i != 0 {
context.write_str(", ");
}
match p {
&PartialAssignmentLHS::Table { table, index } => {
context.write_reg(table);
match index {
RK::R(reg) => {
context.write_str("[");
context.write_reg(reg);
context.write_str("]");
},
RK::K(constant) => {
let valid_name = context.is_valid_name(constant);
if valid_name {
context.write_str(".");
context.write_name(constant);
} else {
context.write_str("[");
context.write_constant(constant);
context.write_str("]");
}
},
}
},
&PartialAssignmentLHS::Global(kst) => {
context.write_name(kst);
},
&PartialAssignmentLHS::Upvalue(upval) => {
context.write_upvalue(upval);
},
&PartialAssignmentLHS::Local(reg) => {
context.write_reg(reg);
},
&PartialAssignmentLHS::Multi { base, count } => {
context.write_str("[");
context.write_reg(base);
context.write_str("..");
context.write_reg(Reg(base.0 + count - 1));
context.write_str("]");
}
}
}
}
fn format_full_lhs(context: &mut dyn DumpContext, full: &Vec<FullAssignmentLHS>) {
for (i, f) in full.iter().rev().enumerate() {
if i != 0 {
context.write_str(", ");
}
match f {
&FullAssignmentLHS::Table { table, index } => {
table.dump(context);
index.dump_index(context);
},
&FullAssignmentLHS::Global(kst) => {
context.write_name(kst);
},
&FullAssignmentLHS::Upvalue(upval) => {
context.write_upvalue(upval);
},
&FullAssignmentLHS::Local(reg) => {
context.write_reg(reg);
}
}
}
}
}
#[derive(Debug, Clone)]
pub enum PartialAssignmentLHS {
Table {
table: Reg,
index: RK
},
Global(Kst),
Upvalue(Upvalue),
Local(Reg),
Multi {
base: Reg,
count: u8
}
}
impl PartialAssignmentLHS {
pub fn pull_base_reg(&self) -> Option<Reg> {
if let &PartialAssignmentLHS::Table {table, index} = &self {
Some(if let RK::R(index_reg) = index {
if index_reg.is_above(*table) {
*index_reg
} else {
*table
}
} else {
*table
})
} else {
None
}
}
pub fn can_convert_to_full(&self) -> bool {
match &self {
&PartialAssignmentLHS::Multi { .. } => false,
_ => true
}
}
pub fn to_full(self, builder: &mut ViewBuilder) -> FullAssignmentLHS {
match self {
PartialAssignmentLHS::Table { table, index } => {
let index_view = builder.take_reg_or_kst(index);
let table_view = builder.take_reg(table);
FullAssignmentLHS::Table {
table: table_view,
index: index_view
}
},
PartialAssignmentLHS::Global(k) => FullAssignmentLHS::Global(k),
PartialAssignmentLHS::Upvalue(u) => FullAssignmentLHS::Upvalue(u),
PartialAssignmentLHS::Local(r) => FullAssignmentLHS::Local(r),
PartialAssignmentLHS::Multi { .. } => panic!("Cannot convert {:?} to full assignment", self)
}
}
}
#[derive(Debug, Clone)]
pub enum FullAssignmentLHS {
Table {
table: ViewOrReg,
index: ViewOrRegOrKst
},
Global(Kst),
Upvalue(Upvalue),
Local(Reg)
}
#[derive(Debug, Clone)]
pub enum AssignmentLHS {
Partial(Vec<PartialAssignmentLHS>),
Full(Vec<FullAssignmentLHS>)
}