use crate::context::Context;
use crate::generics::GenericUser;
use crate::instance::ObjectInstance;
use crate::instruction::FunctionCall;
use crate::instruction::{InstrKind, Instruction};
use crate::location::SpanTuple;
use crate::typechecker::{CheckedType, TypeCheck, TypeCtx};
#[derive(Clone)]
pub struct MethodCall {
var: Box<dyn Instruction>,
method: FunctionCall,
cached_type: Option<CheckedType>,
location: Option<SpanTuple>,
}
impl MethodCall {
pub fn new(var: Box<dyn Instruction>, method: FunctionCall) -> MethodCall {
MethodCall {
var,
method,
cached_type: None,
location: None,
}
}
pub fn set_location(&mut self, location: SpanTuple) {
self.location = Some(location)
}
}
impl Instruction for MethodCall {
fn kind(&self) -> InstrKind {
InstrKind::Expression(None)
}
fn print(&self) -> String {
format!("{}.{}", self.var.print(), self.method.print())
}
fn execute(&self, ctx: &mut Context) -> Option<ObjectInstance> {
let mut call = self.method.clone();
call.add_arg_front(self.var.clone());
if let Some(loc) = &self.location {
call.set_location(loc.clone())
};
call.execute(ctx)
}
fn location(&self) -> Option<&SpanTuple> {
self.location.as_ref()
}
}
impl TypeCheck for MethodCall {
fn resolve_type(&mut self, ctx: &mut TypeCtx) -> CheckedType {
let mut call = self.method.clone();
call.add_arg_front(self.var.clone());
if let Some(loc) = &self.location {
call.set_location(loc.clone())
};
let res = call.type_of(ctx);
self.method.set_name(call.name().to_string());
res
}
fn set_cached_type(&mut self, ty: CheckedType) {
self.cached_type = Some(ty)
}
fn cached_type(&self) -> Option<&CheckedType> {
self.cached_type.as_ref()
}
}
impl GenericUser for MethodCall {
fn resolve_usages(&mut self, type_map: &crate::generics::GenericMap, ctx: &mut TypeCtx) {
self.method.resolve_usages(type_map, ctx);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::instance::ToObjectInstance;
use crate::parser::constructs;
use crate::value::JkInt;
use crate::{jinko, span};
#[test]
fn t_print() {
let var = Box::new(JkInt::from(15));
let method = FunctionCall::new("some_int_func".to_owned(), vec![], vec![]);
let mc = MethodCall::new(var, method);
assert_eq!(mc.print(), "15.some_int_func()".to_owned())
}
#[test]
fn t_execute() {
let mut ctx = Context::new(Box::new(crate::io_trait::JkStdReader));
let mut func_dec = constructs::expr(span!("func __first(a: int, b: int) -> int { a }"))
.unwrap()
.1;
ctx.type_check(&mut *func_dec).unwrap();
func_dec.execute(&mut ctx);
let var1 = Box::new(JkInt::from(1));
let var2 = Box::new(JkInt::from(2));
let method = FunctionCall::new("__first".to_owned(), vec![], vec![var2]);
let mut mc = MethodCall::new(var1, method);
ctx.type_check(&mut mc).unwrap();
assert_eq!(mc.execute(&mut ctx).unwrap(), JkInt::from(1).to_instance());
}
#[test]
fn tc_valid_call() {
jinko! {
func id(x: int) -> int { x }
15.id();
type IntWrapper(inner: int);
i = IntWrapper(inner: 14);
};
}
#[test]
#[ignore] fn tc_valid_call_multi_arg() {
jinko! {
func to_int(self: bool, truthy_value: int) -> int {
if self {
truthy_value
} else {
0
}
}
true.to_int(15);
false.to_int(188);
};
}
#[test]
#[ignore] fn tc_invalid_call_type() {
jinko! {
func id(x: int) -> int { x }
true.id();
};
}
}