use std::fmt;
use debris_error::LangResult;
use super::{obj_class::HasClass, obj_function::FunctionContext, obj_int::ObjInt};
use crate::{
class::ClassRef,
function_interface::make_overload,
impl_class,
llir_nodes::{BinaryOperation, Condition, FastStore, FastStoreFromResult, Node},
memory::MemoryLayout,
minecraft_utils::{ScoreboardComparison, ScoreboardOperation, ScoreboardValue},
objects::{obj_bool::ObjBool, obj_class::ObjClass},
type_context::TypeContext,
ObjectPayload, ObjectRef, Type,
};
macro_rules! bin_op {
($operation:expr, $ctx:ident, $lhs:ident, $rhs:ident) => {
$ctx.emit(Node::BinaryOperation(BinaryOperation {
id: $ctx.item_id,
operation: $operation,
lhs: $lhs.as_scoreboard_value(),
rhs: $rhs.as_scoreboard_value(),
}));
};
}
macro_rules! cmp {
($ctx:expr, $lhs:expr, $rhs:expr, $cmp:expr) => {{
$ctx.emit(Node::FastStoreFromResult(FastStoreFromResult {
id: $ctx.item_id,
command: Box::new(Node::Condition(Condition::Compare {
lhs: $lhs.as_scoreboard_value(),
rhs: $rhs.as_scoreboard_value(),
comparison: $cmp,
})),
}));
$ctx.item_id.into()
}};
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct ObjStaticInt {
pub value: i32,
}
impl_class! {ObjStaticInt, Type::ComptimeInt, {
"abs" => |this: &ObjStaticInt| -> i32 {
this.value.abs()
},
"min" => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Min.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Min, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function()
]),
"max" => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Max.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Max, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function()
]),
Promote => |ctx: &mut FunctionContext, this: &ObjStaticInt, target: &ObjClass| -> Option<LangResult<ObjectRef>> {
match target.class.kind.typ() {
Type::DynamicInt => {
ctx.emit(Node::FastStore(FastStore {
id: ctx.item_id,
value: ScoreboardValue::Static(this.value),
}));
Some(Ok(ObjInt::new(ctx.item_id).into_object(ctx.type_ctx())))
}
_ => None,
}
},
UnaryMinus => |value: &ObjStaticInt| -> i32 {
-value.value
},
Add => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Plus.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Plus, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function(),
]),
Sub => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Minus.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Minus, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function(),
]),
Mul => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Times.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Times, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function(),
]),
Div => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Divide.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Divide, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function(),
]),
Mod => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> i32 {
ScoreboardOperation::Modulo.evaluate(a.value, b.value)
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjInt {
bin_op!(ScoreboardOperation::Modulo, ctx, a, b);
ctx.item_id.into()
}.to_normalized_function(),
]),
CmpEq => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> bool {
a.value == b.value
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjBool {
cmp!(ctx, a, b, ScoreboardComparison::Equal)
}.to_normalized_function()
]),
CmpNe => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> bool {
a.value != b.value
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjBool {
cmp!(ctx, a, b, ScoreboardComparison::NotEqual)
}.to_normalized_function(),
]),
CmpGt => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> bool {
a.value > b.value
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjBool {
if a.value == i32::MIN {
ctx.emit(Node::FastStore(FastStore {
id: ctx.item_id,
value: ScoreboardValue::Static(0),
}));
return ObjBool::new(ctx.item_id);
}
cmp!(ctx, a, b, ScoreboardComparison::Greater)
}.to_normalized_function(),
]),
CmpGe => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> bool {
a.value >= b.value
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjBool {
if a.value == i32::MAX {
ctx.emit(Node::FastStore(FastStore {
id: ctx.item_id,
value: ScoreboardValue::Static(1),
}));
return ObjBool::new(ctx.item_id);
}
cmp!(ctx, a, b, ScoreboardComparison::GreaterOrEqual)
}.to_normalized_function(),
]),
CmpLt => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> bool {
a.value < b.value
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjBool {
if a.value == i32::MAX {
ctx.emit(Node::FastStore(FastStore {
id: ctx.item_id,
value: ScoreboardValue::Static(0),
}));
return ObjBool::new(ctx.item_id);
}
cmp!(ctx, a, b, ScoreboardComparison::Less)
}.to_normalized_function(),
]),
CmpLe => make_overload(vec![
|a: &ObjStaticInt, b: &ObjStaticInt| -> bool {
a.value <= b.value
}.to_normalized_function(),
|ctx: &mut FunctionContext, a: &ObjStaticInt, b: &ObjInt| -> ObjBool {
if a.value == i32::MIN {
ctx.emit(Node::FastStore(FastStore {
id: ctx.item_id,
value: ScoreboardValue::Static(1),
}));
return ObjBool::new(ctx.item_id);
}
cmp!(ctx, a, b, ScoreboardComparison::LessOrEqual)
}.to_normalized_function(),
])
}}
impl ObjStaticInt {
pub fn new(value: impl Into<i32>) -> Self {
ObjStaticInt {
value: value.into(),
}
}
pub fn as_scoreboard_value(&self) -> ScoreboardValue {
ScoreboardValue::Static(self.value)
}
}
impl ObjectPayload for ObjStaticInt {
fn memory_layout(&self) -> &MemoryLayout {
&MemoryLayout::Unsized
}
fn runtime_class(&self, ctx: &TypeContext) -> Option<ClassRef> {
Some(ObjInt::static_class(ctx))
}
}
impl fmt::Display for ObjStaticInt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
}
}
macro_rules! impl_for {
($x:ty, $($xs:tt)*) => {
impl_for!($x);
impl_for!($($xs)*);
};
($x:ty) => {
impl From<$x> for ObjStaticInt {
fn from(value: $x) -> Self {
ObjStaticInt::new(value as i32)
}
}
};
() => {};
}
impl_for!(i8, i16, i32, i64, i128, isize);
impl_for!(u8, u16, u32, u64, u128, usize);