diff --git a/README.md b/README.md index fca8bd2a9614a..4e6fc9f629fd2 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ **I**t's a **N**ew **K**ind of **W**rapper for **E**xposing **LL**VM (*S*afely) -Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys. It provides a more strongly typed interface than LLVM itself so that certain types of errors can be caught at compile time instead of at LLVM's runtime. The ultimate goal is to make LLVM safer from the rust end and a bit easier to learn and use. +Inkwell aims to help you pen your own programming languages by safely wrapping llvm-sys. It provides a more strongly typed interface than the underlying LLVM API so that certain types of errors can be caught at compile time instead of at LLVM's runtime. This means we are trying to replicate LLVM IR's strong typing as closely as possible. The ultimate goal is to make LLVM safer from the rust end and a bit easier to learn (via documentation) and use. ## Documentation diff --git a/src/execution_engine.rs b/src/execution_engine.rs index 5b5fac2b8023f..1072fea325c26 100644 --- a/src/execution_engine.rs +++ b/src/execution_engine.rs @@ -99,6 +99,10 @@ impl ExecutionEngine { } // FIXME: Workaround until we can think of a better API + // Ideally, we'd provide this as a hashmap from module name to module, but this may not be + // possible since you can create modules, ie via create_module_from_ir, which either do not + // have a name, or at least LLVM provides no way to obtain its name. Also, possible collisions + // depending on how loose, if at all, LLVM is with module names belonging to execution engines pub fn get_module_at(&self, index: usize) -> &Module { &self.modules[index] } diff --git a/src/types/float_type.rs b/src/types/float_type.rs index 629df7d7ad789..a3e4b997936d2 100644 --- a/src/types/float_type.rs +++ b/src/types/float_type.rs @@ -1,4 +1,4 @@ -use llvm_sys::core::{LLVMConstReal, LLVMConstNull, LLVMHalfType, LLVMFloatType, LLVMDoubleType, LLVMFP128Type, LLVMPPCFP128Type, LLVMConstRealOfString}; +use llvm_sys::core::{LLVMConstReal, LLVMConstNull, LLVMHalfType, LLVMFloatType, LLVMDoubleType, LLVMFP128Type, LLVMPPCFP128Type, LLVMConstRealOfStringAndSize}; use llvm_sys::execution_engine::LLVMCreateGenericValueOfFloat; use llvm_sys::prelude::LLVMTypeRef; @@ -44,12 +44,9 @@ impl FloatType { } // REVIEW: What happens when string is invalid? Nullptr? - // REVIEW: Difference of LLVMConstRealOfStringAndSize? - pub fn const_float_from_string(&self, string: &str) -> FloatValue { - let c_string = CString::new(string).expect("Conversion to CString failed unexpectedly"); - + pub fn const_float_from_string(&self, slice: &str) -> FloatValue { let value = unsafe { - LLVMConstRealOfString(self.as_type_ref(), c_string.as_ptr()) + LLVMConstRealOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32) }; FloatValue::new(value) diff --git a/src/types/int_type.rs b/src/types/int_type.rs index 03e5c4aed3fb2..8d7097d9a4dd0 100644 --- a/src/types/int_type.rs +++ b/src/types/int_type.rs @@ -1,4 +1,4 @@ -use llvm_sys::core::{LLVMInt1Type, LLVMInt8Type, LLVMInt16Type, LLVMInt32Type, LLVMInt64Type, LLVMConstInt, LLVMConstNull, LLVMConstAllOnes, LLVMIntType, LLVMGetIntTypeWidth, LLVMConstIntOfString}; +use llvm_sys::core::{LLVMInt1Type, LLVMInt8Type, LLVMInt16Type, LLVMInt32Type, LLVMInt64Type, LLVMConstInt, LLVMConstNull, LLVMConstAllOnes, LLVMIntType, LLVMGetIntTypeWidth, LLVMConstIntOfStringAndSize, LLVMConstIntOfArbitraryPrecision}; use llvm_sys::execution_engine::LLVMCreateGenericValueOfInt; use llvm_sys::prelude::LLVMTypeRef; @@ -201,13 +201,19 @@ impl IntType { IntValue::new(value) } - // REVIEW: What happens when string is invalid? Nullptr? - // REVIEW: Difference of LLVMConstIntOfStringAndSize? - pub fn const_int_from_string(&self, string: &str, radix: u8) -> IntValue { - let c_string = CString::new(string).expect("Conversion to CString failed unexpectedly"); + // TODOC: LLVM will parse as best as it can, without any error for invalid input + // ie ("012", 2) => int 1 + pub fn const_int_from_string(&self, slice: &str, radix: u8) -> IntValue { + let value = unsafe { + LLVMConstIntOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32, radix) + }; + + IntValue::new(value) + } + pub fn const_int_arbitrary_precision(&self, words: &[u64]) -> IntValue { let value = unsafe { - LLVMConstIntOfString(self.as_type_ref(), c_string.as_ptr(), radix) + LLVMConstIntOfArbitraryPrecision(self.as_type_ref(), words.len() as u32, words.as_ptr()) }; IntValue::new(value) diff --git a/tests/test_values.rs b/tests/test_values.rs index 6b8f2bfa81b2e..e29f4bdef1d2b 100644 --- a/tests/test_values.rs +++ b/tests/test_values.rs @@ -660,3 +660,26 @@ fn test_function_value_no_params() { assert!(!fn_value.is_null()); assert!(!fn_value.is_undef()); } + +#[test] +fn test_int_from_string() { + let context = Context::create(); + let i8_type = context.i8_type(); + let i8_val = i8_type.const_int_from_string("0121", 10); + + assert_eq!(i8_val.print_to_string(), &*CString::new("i8 121").unwrap()); + + let i8_val = i8_type.const_int_from_string("0121", 3); + + assert_eq!(i8_val.print_to_string(), &*CString::new("i8 16").unwrap()); + + // LLVM will not throw an error, just parse until it can parse no more (and + // possibly spit out something completely unexpected): + let i8_val = i8_type.const_int_from_string("0121", 2); + + assert_eq!(i8_val.print_to_string(), &*CString::new("i8 3").unwrap()); + + let i8_val = i8_type.const_int_from_string("ABCD", 2); + + assert_eq!(i8_val.print_to_string(), &*CString::new("i8 -15").unwrap()); +}