diff --git a/src/builtins.rs b/src/builtins.rs index de9060b..c46c9aa 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -79,10 +79,28 @@ pub(crate) fn print(vm: &mut Vm, state: FunctionState) -> FunctionResult { } //////////////////////////////////////////////////////////////////////////////// -// Base function implementations +// BaseObjInst implementations //////////////////////////////////////////////////////////////////////////////// impl BaseObjInst { + // + // Common functions + // + + pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let str_value = format!("{}", vm.frame_stack()[0].borrow()); + vm.create_str(str_value).into() + } + + pub(crate) fn to_bool(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + vm.create_bool(vm.frame_stack()[0].borrow().is_truthy()) + .into() + } + + // + // Operators + // + pub(crate) fn and(vm: &mut Vm, _state: FunctionState) -> FunctionResult { let lhs = vm.frame_stack()[0].borrow(); let rhs = vm.frame_stack()[1].borrow(); @@ -149,15 +167,9 @@ impl BaseObjInst { } } - pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult { - let str_value = format!("{}", vm.frame_stack()[0].borrow()); - vm.create_str(str_value).into() - } - - pub(crate) fn to_bool(vm: &mut Vm, _state: FunctionState) -> FunctionResult { - vm.create_bool(vm.frame_stack()[0].borrow().is_truthy()) - .into() - } + // + // Not implemented + // pub(crate) fn not_implemented_un(vm: &mut Vm, _state: FunctionState) -> FunctionResult { let fname = &vm.frame().name; @@ -175,5 +187,60 @@ impl BaseObjInst { } //////////////////////////////////////////////////////////////////////////////// -// +// StringInst implementations //////////////////////////////////////////////////////////////////////////////// +impl StrInst { + pub(crate) fn to_str(_vm: &mut Vm, _state: FunctionState) -> FunctionResult { + // top item of the stack should just be ourselves, so return immediately + FunctionResult::Return + } + + pub(crate) fn to_repr(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let escaped: String = + with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| { + str_inst.str_value().as_str().escape_default().collect() + }); + vm.create_str(escaped).into() + } + + pub(crate) fn len(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let len = with_obj_downcast(vm.frame_stack()[0].clone(), |str_inst: &StrInst| { + str_inst.str_value().len() as i64 + }); + vm.create_int(len).into() + } + + pub(crate) fn add(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let lhs = vm.frame_stack()[0].clone(); + let rhs = vm.frame_stack()[1].clone(); + if !obj_is_inst::(&rhs) { + // TODO StrInst::add - throw an exception when the RHS is not a string + // BLOCKED-ON: exceptions + todo!( + "can only concatenate Str, got {} instead", + rhs.borrow().type_name() + ) + } + + let new = format!("{}{}", lhs.borrow(), rhs.borrow()); + vm.create_str(new).into() + } + + pub(crate) fn mul(vm: &mut Vm, _state: FunctionState) -> FunctionResult { + let lhs = vm.frame_stack()[0].clone(); + let rhs = vm.frame_stack()[1].clone(); + let repeat_count = if let Some(int_inst) = rhs.borrow().as_any().downcast_ref::() { + int_inst.int_value() + } else { + // TODO StrInst::mul - throw an exception when the RHS is not an int + // BLOCKED-ON: exceptions + todo!( + "can only repeat Str with Int, got {} instead", + rhs.borrow().type_name() + ) + }; + let repeat_count = repeat_count.max(0) as usize; + let new = format!("{}", lhs.borrow()).repeat(repeat_count); + vm.create_str(new).into() + } +} diff --git a/src/obj.rs b/src/obj.rs index 7fea000..70ad0e9 100644 --- a/src/obj.rs +++ b/src/obj.rs @@ -116,9 +116,10 @@ pub fn init_types(builtins: &mut HashMap) { // type definitions Type { // Method conversion - to_string => builtins.create_builtin_function("to_string", BaseObjInst::to_repr, 1), + to_str => builtins.create_builtin_function("to_str", BaseObjInst::to_repr, 1), to_repr => builtins.create_builtin_function("to_repr", BaseObjInst::to_repr, 1), to_bool => builtins.create_builtin_function("to_bool", BaseObjInst::to_bool, 1), + len => builtins.create_builtin_function("len", BaseObjInst::not_implemented_un, 1), // Operators __add__ => builtins.create_builtin_function("__add__", BaseObjInst::not_implemented_bin, 2), __sub__ => builtins.create_builtin_function("__sub__", BaseObjInst::not_implemented_bin, 2), @@ -137,7 +138,14 @@ pub fn init_types(builtins: &mut HashMap) { __not__ => builtins.create_builtin_function("__not__", BaseObjInst::not, 1), }, Obj { }, - Str { }, + Str { + to_str => builtins.create_builtin_function("to_str", StrInst::to_str, 1), + to_repr => builtins.create_builtin_function("to_repr", StrInst::to_repr, 1), + len => builtins.create_builtin_function("len", StrInst::len, 1), + // Operators + __add__ => builtins.create_builtin_function("__add__", StrInst::add, 2), + __mul__ => builtins.create_builtin_function("__mul__", StrInst::mul, 2), + }, Int { }, Float { }, Bool { }, @@ -824,7 +832,7 @@ fn test_obj_vtable() { let to_string_ptr = str1.borrow_mut().get_attr_lazy( str1.clone(), builtins.get("Method").unwrap().clone(), - "to_string", + "to_str", ); assert!(to_string_ptr.is_some()); @@ -838,7 +846,7 @@ fn test_obj_vtable() { let method_to_string_ptr = to_string_ptr.borrow_mut().get_attr_lazy( to_string_ptr.clone(), builtins.get("Method").unwrap().clone(), - "to_string", + "to_str", ); assert!(method_to_string_ptr.is_some());