Skip to content

Commit c9a751b

Browse files
committed
Added int/float from string support
Added arbitrary precision int. Test for int from string
1 parent 6a7b508 commit c9a751b

File tree

5 files changed

+43
-13
lines changed

5 files changed

+43
-13
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
**I**t's a **N**ew **K**ind of **W**rapper for **E**xposing **LL**VM (*S*afely)
99

10-
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.
10+
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.
1111

1212
## Documentation
1313

src/execution_engine.rs

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ impl ExecutionEngine {
9999
}
100100

101101
// FIXME: Workaround until we can think of a better API
102+
// Ideally, we'd provide this as a hashmap from module name to module, but this may not be
103+
// possible since you can create modules, ie via create_module_from_ir, which either do not
104+
// have a name, or at least LLVM provides no way to obtain its name. Also, possible collisions
105+
// depending on how loose, if at all, LLVM is with module names belonging to execution engines
102106
pub fn get_module_at(&self, index: usize) -> &Module {
103107
&self.modules[index]
104108
}

src/types/float_type.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use llvm_sys::core::{LLVMConstReal, LLVMConstNull, LLVMHalfType, LLVMFloatType, LLVMDoubleType, LLVMFP128Type, LLVMPPCFP128Type, LLVMConstRealOfString};
1+
use llvm_sys::core::{LLVMConstReal, LLVMConstNull, LLVMHalfType, LLVMFloatType, LLVMDoubleType, LLVMFP128Type, LLVMPPCFP128Type, LLVMConstRealOfStringAndSize};
22
use llvm_sys::execution_engine::LLVMCreateGenericValueOfFloat;
33
use llvm_sys::prelude::LLVMTypeRef;
44

@@ -44,12 +44,9 @@ impl FloatType {
4444
}
4545

4646
// REVIEW: What happens when string is invalid? Nullptr?
47-
// REVIEW: Difference of LLVMConstRealOfStringAndSize?
48-
pub fn const_float_from_string(&self, string: &str) -> FloatValue {
49-
let c_string = CString::new(string).expect("Conversion to CString failed unexpectedly");
50-
47+
pub fn const_float_from_string(&self, slice: &str) -> FloatValue {
5148
let value = unsafe {
52-
LLVMConstRealOfString(self.as_type_ref(), c_string.as_ptr())
49+
LLVMConstRealOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32)
5350
};
5451

5552
FloatValue::new(value)

src/types/int_type.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use llvm_sys::core::{LLVMInt1Type, LLVMInt8Type, LLVMInt16Type, LLVMInt32Type, LLVMInt64Type, LLVMConstInt, LLVMConstNull, LLVMConstAllOnes, LLVMIntType, LLVMGetIntTypeWidth, LLVMConstIntOfString};
1+
use llvm_sys::core::{LLVMInt1Type, LLVMInt8Type, LLVMInt16Type, LLVMInt32Type, LLVMInt64Type, LLVMConstInt, LLVMConstNull, LLVMConstAllOnes, LLVMIntType, LLVMGetIntTypeWidth, LLVMConstIntOfStringAndSize, LLVMConstIntOfArbitraryPrecision};
22
use llvm_sys::execution_engine::LLVMCreateGenericValueOfInt;
33
use llvm_sys::prelude::LLVMTypeRef;
44

@@ -201,13 +201,19 @@ impl IntType {
201201
IntValue::new(value)
202202
}
203203

204-
// REVIEW: What happens when string is invalid? Nullptr?
205-
// REVIEW: Difference of LLVMConstIntOfStringAndSize?
206-
pub fn const_int_from_string(&self, string: &str, radix: u8) -> IntValue {
207-
let c_string = CString::new(string).expect("Conversion to CString failed unexpectedly");
204+
// TODOC: LLVM will parse as best as it can, without any error for invalid input
205+
// ie ("012", 2) => int 1
206+
pub fn const_int_from_string(&self, slice: &str, radix: u8) -> IntValue {
207+
let value = unsafe {
208+
LLVMConstIntOfStringAndSize(self.as_type_ref(), slice.as_ptr() as *const i8, slice.len() as u32, radix)
209+
};
210+
211+
IntValue::new(value)
212+
}
208213

214+
pub fn const_int_arbitrary_precision(&self, words: &[u64]) -> IntValue {
209215
let value = unsafe {
210-
LLVMConstIntOfString(self.as_type_ref(), c_string.as_ptr(), radix)
216+
LLVMConstIntOfArbitraryPrecision(self.as_type_ref(), words.len() as u32, words.as_ptr())
211217
};
212218

213219
IntValue::new(value)

tests/test_values.rs

+23
Original file line numberDiff line numberDiff line change
@@ -660,3 +660,26 @@ fn test_function_value_no_params() {
660660
assert!(!fn_value.is_null());
661661
assert!(!fn_value.is_undef());
662662
}
663+
664+
#[test]
665+
fn test_int_from_string() {
666+
let context = Context::create();
667+
let i8_type = context.i8_type();
668+
let i8_val = i8_type.const_int_from_string("0121", 10);
669+
670+
assert_eq!(i8_val.print_to_string(), &*CString::new("i8 121").unwrap());
671+
672+
let i8_val = i8_type.const_int_from_string("0121", 3);
673+
674+
assert_eq!(i8_val.print_to_string(), &*CString::new("i8 16").unwrap());
675+
676+
// LLVM will not throw an error, just parse until it can parse no more (and
677+
// possibly spit out something completely unexpected):
678+
let i8_val = i8_type.const_int_from_string("0121", 2);
679+
680+
assert_eq!(i8_val.print_to_string(), &*CString::new("i8 3").unwrap());
681+
682+
let i8_val = i8_type.const_int_from_string("ABCD", 2);
683+
684+
assert_eq!(i8_val.print_to_string(), &*CString::new("i8 -15").unwrap());
685+
}

0 commit comments

Comments
 (0)