use eclisp::{Lisp, LispClass, LispError, lisp_impl};
#[derive(LispClass)]
#[lisp(name = "player", impl)]
struct Player {
#[lisp]
health: i32,
#[lisp(name = "movement-speed")]
speed: f32,
}
#[lisp_impl]
impl Player {
#[method]
fn is_alive(&self) -> bool {
self.health > 0
}
#[method]
fn max_health() -> i32 {
100
}
#[method]
fn label(&self, prefix: String) -> String {
format!("{prefix}:{}", self.health)
}
#[method]
fn checked_health(&self) -> Result<i32, LispError> {
Ok(self.health)
}
#[method]
fn check_damage(&self, amount: i32) -> Result<(), LispError> {
if amount < 0 {
return Err(LispError::RuntimeError("Negative damage".into()));
}
Ok(())
}
}
#[lisp_impl(name = "player_combat")]
impl Player {
#[method]
fn damage(&mut self, amount: i32) {
self.health -= amount;
}
}
fn main() -> Result<(), LispError> {
let lisp = Lisp::new()?;
lisp.enter(|ctx| {
ctx.defclass(Player::class())?;
ctx.defimpl(player_combat::methods())?;
let mut player = Player {
health: 100,
speed: 2.0,
};
println!("Player before:");
println!(" Health: {}", player.health);
println!(" Speed: {}", player.speed);
ctx.with(&mut player, |obj| {
let amount = ctx.int(25)?;
ctx.call("player-damage", &[obj, &amount])?;
println!("\nCalled (player-damage player 25)");
let alive = ctx.call("player-is-alive", &[obj])?;
println!("Player is alive: {}", alive.try_as_bool()?);
let prefix = ctx.string("hp")?;
let label = ctx.call("player-label", &[obj, &prefix])?;
println!("Player label: {}", label.try_as_string()?);
let health = ctx.call("player-checked-health", &[obj])?;
println!("Checked health: {}", health.try_as_i64()?);
let speed = ctx.call("player-movement-speed", &[obj])?;
println!("Movement speed: {}", speed.try_as_f64()?);
Ok::<(), LispError>(())
})?;
let maximum = ctx.eval("(player-max-health)")?;
println!("Maximum health: {}", maximum.try_as_i64()?);
println!("\nPlayer after:");
println!(" Health: {}", player.health);
println!(" Speed: {}", player.speed);
Ok::<(), LispError>(())
})
}