use super::*;
use crate::error::Error;
use crate::reader::Offset;
#[derive(Debug)]
#[allow(dead_code)]
pub enum Usage {
Load {
name: String,
offset: Option<Offset>,
},
CallOrCopy {
name: String,
offset: Option<Offset>,
},
Call {
name: String,
args: usize,
nargs: usize,
offset: Option<Offset>,
},
Error(Error),
}
impl Usage {
pub fn try_resolve(&mut self, compiler: &mut Compiler) -> Option<Vec<ImlOp>> {
let mut ret: Vec<ImlOp> = Vec::new();
match self {
Usage::Load { name, offset: _ } => {
if let Some(value) = compiler.get_constant(&name) {
ret.push(Op::LoadStatic(compiler.define_value(value)).into());
} else if let Some(addr) = compiler.get_local(&name) {
ret.push(Op::LoadFast(addr).into())
} else if let Some(addr) = compiler.get_global(&name) {
ret.push(Op::LoadGlobal(addr).into())
}
}
Usage::CallOrCopy { name, offset } => {
if let Some(value) = compiler.get_constant(&name) {
if value.is_callable(true) {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
ret.push(Op::CallStatic(compiler.define_value(value)).into());
} else {
ret.push(Op::LoadStatic(compiler.define_value(value)).into());
}
} else if let Some(addr) = compiler.get_local(&name) {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
ret.push(Op::LoadFast(addr).into());
ret.push(Op::CallOrCopy.into());
} else if let Some(addr) = compiler.get_global(&name) {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
ret.push(Op::LoadGlobal(addr).into());
ret.push(Op::CallOrCopy.into());
}
}
Usage::Call {
name,
args,
nargs,
offset,
} => {
if let Some(value) = compiler.get_constant(&name) {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
let addr = compiler.define_value(value);
if *args == 0 && *nargs == 0 {
ret.push(Op::CallStatic(addr).into());
} else if *args > 0 && *nargs == 0 {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
ret.push(Op::CallStaticArg(Box::new((addr, *args))).into());
} else {
ret.push(Op::CallStaticArgNamed(Box::new((addr, *args))).into());
}
} else if let Some(addr) = compiler.get_local(&name) {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
if *args == 0 && *nargs == 0 {
ret.push(Op::LoadFast(addr).into());
ret.push(Op::Call.into());
} else if *args > 0 && *nargs == 0 {
ret.push(Op::LoadFast(addr).into());
ret.push(Op::CallArg(*args).into());
} else {
ret.push(Op::LoadFast(addr).into());
ret.push(Op::CallArgNamed(*args).into());
}
} else if let Some(addr) = compiler.get_global(&name) {
if let Some(offset) = offset {
ret.push(Op::Offset(Box::new(*offset)).into());
}
if *args == 0 && *nargs == 0 {
ret.push(Op::LoadGlobal(addr).into());
ret.push(Op::Call.into());
} else if *args > 0 && *nargs == 0 {
ret.push(Op::LoadGlobal(addr).into());
ret.push(Op::CallArg(*args).into());
} else {
ret.push(Op::LoadGlobal(addr).into());
ret.push(Op::CallArgNamed(*args).into());
}
}
}
Usage::Error(_) => {
}
}
if ret.len() > 0 {
Some(ret)
} else {
None
}
}
pub fn resolve_or_dispose(mut self, compiler: &mut Compiler) -> Vec<ImlOp> {
if let Some(res) = self.try_resolve(compiler) {
res
} else {
compiler.usages.push(Err(self));
vec![ImlOp::Usage(compiler.usages.len() - 1)]
}
}
}