Skip to content

Commit

Permalink
Added int/float from string support
Browse files Browse the repository at this point in the history
Added arbitrary precision int. Test for int from string
  • Loading branch information
TheDan64 committed Sep 28, 2017
1 parent 6a7b508 commit c9a751b
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 13 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions src/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}
Expand Down
9 changes: 3 additions & 6 deletions src/types/float_type.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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)
Expand Down
18 changes: 12 additions & 6 deletions src/types/int_type.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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)
Expand Down
23 changes: 23 additions & 0 deletions tests/test_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

0 comments on commit c9a751b

Please sign in to comment.