diff --git a/runtime/interpreter/src/expressions.rs b/runtime/interpreter/src/expressions.rs index 6611d3e0..8f2a8282 100644 --- a/runtime/interpreter/src/expressions.rs +++ b/runtime/interpreter/src/expressions.rs @@ -258,7 +258,7 @@ impl AstVisitor for Interpreter { } Expression::Ask(ask) => { let prompt_val = self.visit_expression(&ask.prompt)?; - let ask_fn = self.ctx.registry.lookup("ask").unwrap(); + let ask_fn = self.ctx.registry.lookup("ask").ok_or_else(|| crate::RuntimeError::new(crate::RuntimeErrorKind::UndefinedVariable("ask".to_string()), None, None))?; ask_fn.call(&mut self.ctx, vec![prompt_val]) } Expression::Lambda(lambda) => { diff --git a/runtime/interpreter/src/statements.rs b/runtime/interpreter/src/statements.rs index f6e80545..303c54d6 100644 --- a/runtime/interpreter/src/statements.rs +++ b/runtime/interpreter/src/statements.rs @@ -169,7 +169,7 @@ impl Interpreter { } Statement::Say(say_stmt) => { let val = self.visit_expression(&say_stmt.value)?; - let say_func = self.ctx.registry.lookup("say").unwrap(); + let say_func = self.ctx.registry.lookup("say").ok_or_else(|| RuntimeError::new(RuntimeErrorKind::UndefinedVariable("say".to_string()), None, None))?; say_func.call(&mut self.ctx, vec![val])?; Ok(FlowSignal::Normal) } @@ -241,7 +241,7 @@ impl Interpreter { }) } } - let arity = variant.payload.as_ref().unwrap().len(); + let arity = variant.payload.as_ref().map_or(0, |p| p.len()); entries.insert( var_name.clone(), RuntimeValue::Function(Rc::new(VariantConstructor { diff --git a/runtime/native_runtime/src/lib.rs b/runtime/native_runtime/src/lib.rs index 5c39d318..3d829fcc 100644 --- a/runtime/native_runtime/src/lib.rs +++ b/runtime/native_runtime/src/lib.rs @@ -201,6 +201,9 @@ pub unsafe extern "C" fn ts_free_value(val: *mut TsValue) { return; } let value = Box::from_raw(val); + if value.data.pointer.is_null() { + return; + } if value.tag == TsTag::String as u32 { let _ = Box::from_raw(value.data.pointer as *mut String); } else if value.tag == TsTag::List as u32 { @@ -244,41 +247,65 @@ unsafe fn value_to_string(val: *mut TsValue) -> String { } else if v.tag == TsTag::Float as u32 { v.data.float.to_string() } else if v.tag == TsTag::String as u32 { - (*(v.data.pointer as *const String)).clone() + if v.data.pointer.is_null() { + "null".to_string() + } else { + (*(v.data.pointer as *const String)).clone() + } } else if v.tag == TsTag::List as u32 { - let list = &*(v.data.pointer as *const Vec<*mut TsValue>); - let mut parts = Vec::new(); - for &item in list { - parts.push(value_to_string(item)); + if v.data.pointer.is_null() { + "[]".to_string() + } else { + let list = &*(v.data.pointer as *const Vec<*mut TsValue>); + let mut parts = Vec::new(); + for &item in list { + parts.push(value_to_string(item)); + } + format!("[{}]", parts.join(", ")) } - format!("[{}]", parts.join(", ")) } else if v.tag == TsTag::Map as u32 { - let map = &*(v.data.pointer as *const HashMap); - let mut parts = Vec::new(); - for (k, &val) in map { - parts.push(format!("{}: {}", k, value_to_string(val))); + if v.data.pointer.is_null() { + "{}".to_string() + } else { + let map = &*(v.data.pointer as *const HashMap); + let mut parts = Vec::new(); + for (k, &val) in map { + parts.push(format!("{}: {}", k, value_to_string(val))); + } + format!("{{{}}}", parts.join(", ")) } - format!("{{{}}}", parts.join(", ")) } else if v.tag == TsTag::Struct as u32 { - let s = &*(v.data.pointer as *const TsStruct); - let mut parts = Vec::new(); - for (k, &val) in &s.fields { - parts.push(format!("{}: {}", k, value_to_string(val))); + if v.data.pointer.is_null() { + "unknown struct".to_string() + } else { + let s = &*(v.data.pointer as *const TsStruct); + let mut parts = Vec::new(); + for (k, &val) in &s.fields { + parts.push(format!("{}: {}", k, value_to_string(val))); + } + format!("{} {{{}}}", s.name, parts.join(", ")) } - format!("{} {{{}}}", s.name, parts.join(", ")) } else if v.tag == TsTag::Model as u32 { - let m = &*(v.data.pointer as *const TsModel); - let mut parts = Vec::new(); - for (k, &val) in &m.fields { - parts.push(format!("{}: {}", k, value_to_string(val))); + if v.data.pointer.is_null() { + "unknown model".to_string() + } else { + let m = &*(v.data.pointer as *const TsModel); + let mut parts = Vec::new(); + for (k, &val) in &m.fields { + parts.push(format!("{}: {}", k, value_to_string(val))); + } + format!("{} {{{}}}", m.name, parts.join(", ")) } - format!("{} {{{}}}", m.name, parts.join(", ")) } else if v.tag == TsTag::Enum as u32 { - let e = &*(v.data.pointer as *const TsEnum); - if e.value.is_null() { - format!("{}.{}", e.name, e.variant) + if v.data.pointer.is_null() { + "unknown enum".to_string() } else { - format!("{}.{}({})", e.name, e.variant, value_to_string(e.value)) + let e = &*(v.data.pointer as *const TsEnum); + if e.value.is_null() { + format!("{}.{}", e.name, e.variant) + } else { + format!("{}.{}({})", e.name, e.variant, value_to_string(e.value)) + } } } else { "unknown".to_string() diff --git a/runtime/vm/src/executor.rs b/runtime/vm/src/executor.rs index a800df31..90083e26 100644 --- a/runtime/vm/src/executor.rs +++ b/runtime/vm/src/executor.rs @@ -36,7 +36,7 @@ impl VM { if self.debugger.is_enabled() { let current_func = - &self.module.functions[self.frames.last().unwrap().function_idx as usize]; + &self.module.functions[self.frames.last().ok_or(crate::error::VMError::StackUnderflow)?.function_idx as usize]; self.debugger.trace_instruction( current_func, ip, @@ -52,7 +52,7 @@ impl VM { Opcode::LoadConst => { if let Some(Operand::ConstantIndex(c_idx)) = inst_operands.first() { let current_func = &self.module.functions - [self.frames.last().unwrap().function_idx as usize]; + [self.frames.last().ok_or(crate::error::VMError::StackUnderflow)?.function_idx as usize]; let lit = current_func .chunk .constants @@ -73,7 +73,7 @@ impl VM { Opcode::LoadLocal => { if let Some(Operand::LocalIndex(l_idx)) = inst_operands.first() { - let bp = self.frames.last().unwrap().base_pointer; + let bp = self.frames.last().ok_or(crate::error::VMError::StackUnderflow)?.base_pointer; let val = self.stack.get(bp + *l_idx as usize)?; self.stack.push(val.clone())?; } else { @@ -83,7 +83,7 @@ impl VM { Opcode::StoreLocal => { if let Some(Operand::LocalIndex(l_idx)) = inst_operands.first() { - let bp = self.frames.last().unwrap().base_pointer; + let bp = self.frames.last().ok_or(crate::error::VMError::StackUnderflow)?.base_pointer; let val = self.stack.pop()?; self.stack.set(bp + *l_idx as usize, val)?; } else { @@ -769,7 +769,7 @@ impl VM { Opcode::FieldLoad => { if let Some(Operand::ConstantIndex(c_idx)) = inst_operands.first() { let current_func = &self.module.functions - [self.frames.last().unwrap().function_idx as usize]; + [self.frames.last().ok_or(crate::error::VMError::StackUnderflow)?.function_idx as usize]; let lit = current_func .chunk .constants @@ -827,7 +827,7 @@ impl VM { Opcode::FieldStore => { if let Some(Operand::ConstantIndex(c_idx)) = inst_operands.first() { let current_func = &self.module.functions - [self.frames.last().unwrap().function_idx as usize]; + [self.frames.last().ok_or(crate::error::VMError::StackUnderflow)?.function_idx as usize]; let lit = current_func .chunk .constants diff --git a/tools/package-manager/src/lib.rs b/tools/package-manager/src/lib.rs index 23abd98b..053c923a 100644 --- a/tools/package-manager/src/lib.rs +++ b/tools/package-manager/src/lib.rs @@ -431,18 +431,21 @@ impl DocExtractor { let sym_name = raw_name .split('(') .next() - .unwrap() + .unwrap_or("") .split('{') .next() - .unwrap() + .unwrap_or("") .split('=') .next() - .unwrap() + .unwrap_or("") .trim(); - items.push(DocItem { - name: sym_name.to_string(), - doc: active_doc.join("\n"), - }); + + if !sym_name.is_empty() { + items.push(DocItem { + name: sym_name.to_string(), + doc: active_doc.join("\n"), + }); + } } active_doc.clear(); }