Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Use impl hack to fix rational #83

Merged
merged 1 commit into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ impl<'llvm> Types<'llvm> {
self.llvm.opaque_struct_type(name)
}

/// Get wrapper around pointer to opaque impl
fn with_impl(&self, name: &str) -> StructType<'llvm> {
if let Some(ty) = self.llvm.get_struct_type(name) {
return ty;
}

let ty = self.llvm.opaque_struct_type(name);
ty.set_body(&[self.opaque(&format!("{name}Impl")).into()], false);
ty
}

/// LLVM IR for [`Class`](Type::Class) type
pub fn opaque(&self, name: &str) -> PointerType<'llvm> {
self.get_or_add_opaque_struct(name)
Expand All @@ -82,8 +93,8 @@ impl<'llvm> Types<'llvm> {
}

/// LLVM IR for `Rational` type
pub fn rational(&self) -> PointerType<'llvm> {
self.opaque("Rational")
pub fn rational(&self) -> StructType<'llvm> {
self.with_impl("Rational")
}

/// LLVM IR for [`String`](Type::String) type
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/ppl.ppl
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,11 @@ fn destroy <:Integer>
//=================================
// Rational
//=================================
type RationalImpl

@builtin
type Rational
type Rational:
impl: Reference<RationalImpl>

@mangle_as("rational_eq_rational")
fn <:Rational> == <:Rational> -> Bool
Expand Down
109 changes: 67 additions & 42 deletions src/runtime/src/rational.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
use rug::{ops::Pow, Integer, Rational};
use rug::{ops::Pow, Integer};

/// Runtime type information
///
/// # PPL
/// ```no_run
/// type RationalImpl
///
/// @builtin
/// type Rational:
/// impl: Reference<RationalImpl>
/// ```
#[repr(C)]
pub struct Rational {
pub data: *mut rug::Rational,
}

/// Construct [`Rational`](ppl::semantics::Type::Rational) from a C string
#[no_mangle]
pub extern "C" fn rational_from_c_string(str: *const i8) -> *mut Rational {
pub extern "C" fn rational_from_c_string(str: *const i8) -> Rational {
debug_assert!(!str.is_null());

let c_str = unsafe { core::ffi::CStr::from_ptr(str) };
let str = c_str.to_str().unwrap();
let boxed = Box::new(str.parse::<Rational>().unwrap());
Box::into_raw(boxed)
let boxed = Box::new(str.parse::<rug::Rational>().unwrap());
Rational {
data: Box::into_raw(boxed),
}
}

/// Converts `Rational` to `String`
Expand All @@ -18,8 +35,8 @@ pub extern "C" fn rational_from_c_string(str: *const i8) -> *mut Rational {
/// fn <:Rational> as String -> String
/// ```
#[no_mangle]
pub extern "C" fn rational_as_string(r: *const Rational) -> *mut String {
let value = unsafe { r.as_ref().unwrap() };
pub extern "C" fn rational_as_string(r: Rational) -> *mut String {
let value = unsafe { r.data.as_ref().unwrap() };

let boxed = Box::new(maybe_to_decimal_string(value));
Box::into_raw(boxed)
Expand All @@ -32,10 +49,12 @@ pub extern "C" fn rational_as_string(r: *const Rational) -> *mut String {
/// fn - <:Rational> -> Rational
/// ```
#[no_mangle]
pub extern "C" fn minus_rational(r: *const Rational) -> *mut Rational {
let r = unsafe { r.as_ref().unwrap() };
let boxed = Box::new(Rational::from(-r));
Box::into_raw(boxed)
pub extern "C" fn minus_rational(r: Rational) -> Rational {
let r = unsafe { r.data.as_ref().unwrap() };
let boxed = Box::new(rug::Rational::from(-r));
Rational {
data: Box::into_raw(boxed),
}
}

/// Add 2 rationals
Expand All @@ -45,12 +64,14 @@ pub extern "C" fn minus_rational(r: *const Rational) -> *mut Rational {
/// fn <:Rational> + <:Rational> -> Rational
/// ```
#[no_mangle]
pub extern "C" fn rational_plus_rational(x: *const Rational, y: *const Rational) -> *mut Rational {
let x = unsafe { x.as_ref().unwrap() };
let y = unsafe { y.as_ref().unwrap() };
pub extern "C" fn rational_plus_rational(x: Rational, y: Rational) -> Rational {
let x = unsafe { x.data.as_ref().unwrap() };
let y = unsafe { y.data.as_ref().unwrap() };

let boxed = Box::new(Rational::from(x + y));
Box::into_raw(boxed)
let boxed = Box::new(rug::Rational::from(x + y));
Rational {
data: Box::into_raw(boxed),
}
}

/// Multiply 2 rationals
Expand All @@ -60,11 +81,13 @@ pub extern "C" fn rational_plus_rational(x: *const Rational, y: *const Rational)
/// fn <:Rational> * <:Rational> -> Rational
/// ```
#[no_mangle]
pub extern "C" fn rational_star_rational(x: *const Rational, y: *const Rational) -> *mut Rational {
let x = unsafe { x.as_ref().unwrap() };
let y = unsafe { y.as_ref().unwrap() };
let boxed = Box::new(Rational::from(x * y));
Box::into_raw(boxed)
pub extern "C" fn rational_star_rational(x: Rational, y: Rational) -> Rational {
let x = unsafe { x.data.as_ref().unwrap() };
let y = unsafe { y.data.as_ref().unwrap() };
let boxed = Box::new(rug::Rational::from(x * y));
Rational {
data: Box::into_raw(boxed),
}
}

/// Divide 2 rationals
Expand All @@ -74,11 +97,13 @@ pub extern "C" fn rational_star_rational(x: *const Rational, y: *const Rational)
/// fn <:Rational> / <:Rational> -> Rational
/// ```
#[no_mangle]
pub extern "C" fn rational_slash_rational(x: *const Rational, y: *const Rational) -> *mut Rational {
let x = unsafe { x.as_ref().unwrap() };
let y = unsafe { y.as_ref().unwrap() };
let boxed = Box::new(Rational::from(x / y));
Box::into_raw(boxed)
pub extern "C" fn rational_slash_rational(x: Rational, y: Rational) -> Rational {
let x = unsafe { x.data.as_ref().unwrap() };
let y = unsafe { y.data.as_ref().unwrap() };
let boxed = Box::new(rug::Rational::from(x / y));
Rational {
data: Box::into_raw(boxed),
}
}

/// Compare 2 rationals for equality
Expand All @@ -88,9 +113,9 @@ pub extern "C" fn rational_slash_rational(x: *const Rational, y: *const Rational
/// fn <:Rational> == <:Rational> -> Bool
/// ```
#[no_mangle]
pub extern "C" fn rational_eq_rational(x: *const Rational, y: *const Rational) -> bool {
let x = unsafe { x.as_ref().unwrap() };
let y = unsafe { y.as_ref().unwrap() };
pub extern "C" fn rational_eq_rational(x: Rational, y: Rational) -> bool {
let x = unsafe { x.data.as_ref().unwrap() };
let y = unsafe { y.data.as_ref().unwrap() };

x == y
}
Expand All @@ -102,9 +127,9 @@ pub extern "C" fn rational_eq_rational(x: *const Rational, y: *const Rational) -
/// fn <:Rational> < <:Rational> -> Bool
/// ```
#[no_mangle]
pub extern "C" fn rational_less_rational(x: *const Rational, y: *const Rational) -> bool {
let x = unsafe { x.as_ref().unwrap() };
let y = unsafe { y.as_ref().unwrap() };
pub extern "C" fn rational_less_rational(x: Rational, y: Rational) -> bool {
let x = unsafe { x.data.as_ref().unwrap() };
let y = unsafe { y.data.as_ref().unwrap() };
x < y
}

Expand All @@ -113,13 +138,13 @@ pub extern "C" fn rational_less_rational(x: *const Rational, y: *const Rational)
/// fn destroy <:Rational>
/// ```
#[no_mangle]
pub extern "C" fn destroy_rational(x: *mut Rational) {
debug_assert!(!x.is_null());
pub extern "C" fn destroy_rational(x: Rational) {
debug_assert!(!x.data.is_null());

let _ = unsafe { Box::from_raw(x) };
let _ = unsafe { Box::from_raw(x.data) };
}

pub fn maybe_to_decimal_string(r: &Rational) -> String {
pub fn maybe_to_decimal_string(r: &rug::Rational) -> String {
let mut denom = r.denom().clone();
let pow2 = denom.remove_factor_mut(&Integer::from(2));
let pow5 = denom.remove_factor_mut(&Integer::from(5));
Expand Down Expand Up @@ -153,25 +178,25 @@ mod test {
use super::maybe_to_decimal_string;
use rug::Rational;

let r = Rational::from((1, 3));
let r = rug::Rational::from((1, 3));
assert_eq!(maybe_to_decimal_string(&r), "1/3");

let r = Rational::from((1, 2));
let r = rug::Rational::from((1, 2));
assert_eq!(maybe_to_decimal_string(&r), "0.5");

let r = Rational::from((5, 1));
let r = rug::Rational::from((5, 1));
assert_eq!(maybe_to_decimal_string(&r), "5.0");

let r = Rational::from((5, 2));
let r = rug::Rational::from((5, 2));
assert_eq!(maybe_to_decimal_string(&r), "2.5");

let r = Rational::from((1, 4));
let r = rug::Rational::from((1, 4));
assert_eq!(maybe_to_decimal_string(&r), "0.25");

let r = Rational::from((1, 8));
let r = rug::Rational::from((1, 8));
assert_eq!(maybe_to_decimal_string(&r), "0.125");

let r = Rational::from((1, 16));
let r = rug::Rational::from((1, 16));
assert_eq!(maybe_to_decimal_string(&r), "0.0625");
}
}
Loading